diff --git a/docs/src/whatsnew/latest.rst b/docs/src/whatsnew/latest.rst index 0cafd4e94e..10f176e5ca 100644 --- a/docs/src/whatsnew/latest.rst +++ b/docs/src/whatsnew/latest.rst @@ -76,6 +76,10 @@ This document explains the changes made to Iris for this release :meth:`iris.cube.Cube.subset`, and :meth:`iris.coords.Coord.intersect`. (:pull:`4969`) +#. `@bouweandela`_ improved the speed of :meth:`iris.cube.Cube.subset` / + :meth:`iris.coords.Coord.intersect`. + (:pull:`4955`) + 🔥 Deprecations =============== diff --git a/lib/iris/coords.py b/lib/iris/coords.py index ba0ed8ee5d..c2b3349ae9 100644 --- a/lib/iris/coords.py +++ b/lib/iris/coords.py @@ -1345,7 +1345,14 @@ def __add__(self, mod): return Cell(point, bound) def __hash__(self): - return super().__hash__() + # See __eq__ for the definition of when two cells are equal. + if self.bound is None: + return hash(self.point) + bound = self.bound + rbound = bound[::-1] + if rbound < bound: + bound = rbound + return hash((self.point, bound)) def __eq__(self, other): """ @@ -2397,18 +2404,16 @@ def intersect(self, other, return_indices=False): ) raise ValueError(msg) - # Cache self.cells for speed. We can also use the index operation on a - # list conveniently. - self_cells = [cell for cell in self.cells()] + # Cache self.cells for speed. We can also use the dict for fast index + # lookup. + self_cells = {cell: idx for idx, cell in enumerate(self.cells())} # Maintain a list of indices on self for which cells exist in both self # and other. self_intersect_indices = [] for cell in other.cells(): - try: - self_intersect_indices.append(self_cells.index(cell)) - except ValueError: - pass + if cell in self_cells: + self_intersect_indices.append(self_cells[cell]) if return_indices is False and self_intersect_indices == []: raise ValueError( diff --git a/lib/iris/tests/test_cell.py b/lib/iris/tests/test_cell.py index 03d3fa7d7c..21d2603072 100644 --- a/lib/iris/tests/test_cell.py +++ b/lib/iris/tests/test_cell.py @@ -169,9 +169,35 @@ def test_coord_bounds_cmp(self): self.assertTrue(self.e < 2) def test_cell_cell_cmp(self): + self.e = iris.coords.Cell(1) + self.f = iris.coords.Cell(1) + + self.assertTrue(self.e == self.f) + self.assertEqual(hash(self.e), hash(self.f)) + + self.e = iris.coords.Cell(1) + self.f = iris.coords.Cell(1, [0, 2]) + + self.assertFalse(self.e == self.f) + self.assertNotEqual(hash(self.e), hash(self.f)) + + self.e = iris.coords.Cell(1, [0, 2]) + self.f = iris.coords.Cell(1, [0, 2]) + + self.assertTrue(self.e == self.f) + self.assertEqual(hash(self.e), hash(self.f)) + + self.e = iris.coords.Cell(1, [0, 2]) + self.f = iris.coords.Cell(1, [2, 0]) + + self.assertTrue(self.e == self.f) + self.assertEqual(hash(self.e), hash(self.f)) + self.e = iris.coords.Cell(0.7, [1.1, 1.9]) self.f = iris.coords.Cell(0.8, [1.1, 1.9]) + self.assertFalse(self.e == self.f) + self.assertNotEqual(hash(self.e), hash(self.f)) self.assertFalse(self.e > self.f) self.assertTrue(self.e <= self.f) self.assertTrue(self.f >= self.e)