diff --git a/doc/source/whatsnew/v3.0.0.rst b/doc/source/whatsnew/v3.0.0.rst index cc93494645af6..b1e0fb845cb99 100644 --- a/doc/source/whatsnew/v3.0.0.rst +++ b/doc/source/whatsnew/v3.0.0.rst @@ -1042,6 +1042,7 @@ Interval - :meth:`Index.is_monotonic_decreasing`, :meth:`Index.is_monotonic_increasing`, and :meth:`Index.is_unique` could incorrectly be ``False`` for an ``Index`` created from a slice of another ``Index``. (:issue:`57911`) - Bug in :class:`Index`, :class:`Series`, :class:`DataFrame` constructors when given a sequence of :class:`Interval` subclass objects casting them to :class:`Interval` (:issue:`46945`) - Bug in :func:`interval_range` where start and end numeric types were always cast to 64 bit (:issue:`57268`) +- Bug in :meth:`IntervalIndex.get_indexer` and :meth:`IntervalIndex.drop` when one of the sides of the index is non-unique (:issue:`52245`) Indexing ^^^^^^^^ diff --git a/pandas/core/indexes/interval.py b/pandas/core/indexes/interval.py index 063d375f0595f..9cfe27ff81f2c 100644 --- a/pandas/core/indexes/interval.py +++ b/pandas/core/indexes/interval.py @@ -712,7 +712,10 @@ def _get_indexer( # -> at most one match per interval in target # want exact matches -> need both left/right to match, so defer to # left/right get_indexer, compare elementwise, equality -> match - indexer = self._get_indexer_unique_sides(target) + if self.left.is_unique and self.right.is_unique: + indexer = self._get_indexer_unique_sides(target) + else: + indexer = self._get_indexer_pointwise(target)[0] elif not (is_object_dtype(target.dtype) or is_string_dtype(target.dtype)): # homogeneous scalar index: use IntervalTree diff --git a/pandas/tests/indexes/interval/test_indexing.py b/pandas/tests/indexes/interval/test_indexing.py index 5783a16e81d37..79700d09a9c23 100644 --- a/pandas/tests/indexes/interval/test_indexing.py +++ b/pandas/tests/indexes/interval/test_indexing.py @@ -503,6 +503,25 @@ def test_get_indexer_read_only(self): result = idx.get_indexer_non_unique(arr)[0] tm.assert_numpy_array_equal(result, expected, check_dtype=False) + def test_get_indexer_non_unique_right(self): + # GH#52245 + data = [ + Interval(Timestamp("2020-05-26"), Timestamp("2020-05-27")), + Interval(Timestamp("2020-05-27"), Timestamp("2020-05-27")), + ] + + index = IntervalIndex(data) + + result = index.get_indexer([index[0]]) + expected = np.array([0], dtype=np.intp) + tm.assert_numpy_array_equal(result, expected) + + # GH#52245 OP is about drop so we test that here, but the underlying + # problem is in get_indexer. + result = index.drop(index[0]) + expected = index[1:] + tm.assert_index_equal(result, expected) + class TestSliceLocs: def test_slice_locs_with_interval(self):