diff --git a/doc/source/whatsnew/v1.4.0.rst b/doc/source/whatsnew/v1.4.0.rst index d1e209adb1b8f..2d70f361ba9cd 100644 --- a/doc/source/whatsnew/v1.4.0.rst +++ b/doc/source/whatsnew/v1.4.0.rst @@ -515,7 +515,7 @@ Strings Interval ^^^^^^^^ -- +- Bug in :meth:`IntervalIndex.get_indexer_non_unique` returning boolean mask instead of array of integers for a non unique and non monotonic index (:issue:`44084`) - Indexing diff --git a/pandas/core/indexes/interval.py b/pandas/core/indexes/interval.py index 5791f89828ca3..885c922d1ee0f 100644 --- a/pandas/core/indexes/interval.py +++ b/pandas/core/indexes/interval.py @@ -727,6 +727,8 @@ def _get_indexer_pointwise( if isinstance(locs, slice): # Only needed for get_indexer_non_unique locs = np.arange(locs.start, locs.stop, locs.step, dtype="intp") + elif not self.is_unique and not self.is_monotonic: + locs = np.where(locs)[0] locs = np.array(locs, ndmin=1) except KeyError: missing.append(i) diff --git a/pandas/tests/indexes/interval/test_indexing.py b/pandas/tests/indexes/interval/test_indexing.py index 8df8eef69e9c9..75f7c69ce5300 100644 --- a/pandas/tests/indexes/interval/test_indexing.py +++ b/pandas/tests/indexes/interval/test_indexing.py @@ -8,8 +8,10 @@ from pandas import ( NA, CategoricalIndex, + Index, Interval, IntervalIndex, + MultiIndex, NaT, Timedelta, date_range, @@ -373,6 +375,31 @@ def test_get_indexer_with_nans(self): expected = np.array([0, 1], dtype=np.intp) tm.assert_numpy_array_equal(result, expected) + def test_get_index_non_unique_non_monotonic(self): + # GH#44084 (root cause) + index = IntervalIndex.from_tuples( + [(0.0, 1.0), (1.0, 2.0), (0.0, 1.0), (1.0, 2.0)] + ) + + result, _ = index.get_indexer_non_unique([Interval(1.0, 2.0)]) + expected = np.array([1, 3], dtype=np.intp) + tm.assert_numpy_array_equal(result, expected) + + def test_get_indexer_multiindex_with_intervals(self): + # GH#44084 (MultiIndex case as reported) + interval_index = IntervalIndex.from_tuples( + [(2.0, 3.0), (0.0, 1.0), (1.0, 2.0)], name="interval" + ) + foo_index = Index([1, 2, 3], name="foo") + + multi_index = MultiIndex.from_product([foo_index, interval_index]) + + result = multi_index.get_level_values("interval").get_indexer_for( + [Interval(0.0, 1.0)] + ) + expected = np.array([1, 4, 7], dtype=np.intp) + tm.assert_numpy_array_equal(result, expected) + class TestSliceLocs: def test_slice_locs_with_interval(self):