diff --git a/doc/source/api.rst b/doc/source/api.rst index 93edd090d846b..d00e5511f1100 100644 --- a/doc/source/api.rst +++ b/doc/source/api.rst @@ -1632,6 +1632,8 @@ IntervalIndex Components IntervalIndex.length IntervalIndex.values IntervalIndex.is_non_overlapping_monotonic + IntervalIndex.get_loc + IntervalIndex.get_indexer .. _api.multiindex: diff --git a/doc/source/whatsnew/v0.23.0.txt b/doc/source/whatsnew/v0.23.0.txt index 4ad40fe0f7f2b..09ca4f403399b 100644 --- a/doc/source/whatsnew/v0.23.0.txt +++ b/doc/source/whatsnew/v0.23.0.txt @@ -1245,6 +1245,7 @@ Indexing - Bug in ``Series.is_unique`` where extraneous output in stderr is shown if Series contains objects with ``__ne__`` defined (:issue:`20661`) - Bug in ``.loc`` assignment with a single-element list-like incorrectly assigns as a list (:issue:`19474`) - Bug in partial string indexing on a ``Series/DataFrame`` with a monotonic decreasing ``DatetimeIndex`` (:issue:`19362`) +- Bug in :meth:`IntervalIndex.get_loc` and :meth:`IntervalIndex.get_indexer` when used with an :class:`IntervalIndex` containing a single interval (:issue:`17284`, :issue:`20921`) MultiIndex ^^^^^^^^^^ diff --git a/pandas/core/indexes/interval.py b/pandas/core/indexes/interval.py index 54800d0d76d2e..766ac7b14120e 100644 --- a/pandas/core/indexes/interval.py +++ b/pandas/core/indexes/interval.py @@ -159,20 +159,22 @@ class IntervalIndex(IntervalMixin, Index): Attributes ---------- - left - right closed - mid + is_non_overlapping_monotonic + left length + mid + right values - is_non_overlapping_monotonic Methods ------- + contains from_arrays - from_tuples from_breaks - contains + from_tuples + get_indexer + get_loc Examples --------- @@ -938,8 +940,11 @@ def _searchsorted_monotonic(self, label, side, exclude_label=False): if isinstance(label, IntervalMixin): raise NotImplementedError + # GH 20921: "not is_monotonic_increasing" for the second condition + # instead of "is_monotonic_decreasing" to account for single element + # indexes being both increasing and decreasing if ((side == 'left' and self.left.is_monotonic_increasing) or - (side == 'right' and self.left.is_monotonic_decreasing)): + (side == 'right' and not self.left.is_monotonic_increasing)): sub_idx = self.right if self.open_right or exclude_label: label = _get_next_label(label) diff --git a/pandas/tests/indexes/interval/test_interval.py b/pandas/tests/indexes/interval/test_interval.py index 71a6f78125004..9920809a18a24 100644 --- a/pandas/tests/indexes/interval/test_interval.py +++ b/pandas/tests/indexes/interval/test_interval.py @@ -497,6 +497,14 @@ def test_get_loc_interval(self): pytest.raises(KeyError, self.index.get_loc, Interval(-1, 0, 'left')) + # Make consistent with test_interval_new.py (see #16316, #16386) + @pytest.mark.parametrize('item', [3, Interval(1, 4)]) + def test_get_loc_length_one(self, item, closed): + # GH 20921 + index = IntervalIndex.from_tuples([(0, 5)], closed=closed) + result = index.get_loc(item) + assert result == 0 + # To be removed, replaced by test_interval_new.py (see #16316, #16386) def test_get_indexer(self): actual = self.index.get_indexer([-1, 0, 0.5, 1, 1.5, 2, 3]) @@ -544,6 +552,16 @@ def test_get_indexer_subintervals(self): expected = np.array([0, 0, 0], dtype='intp') tm.assert_numpy_array_equal(actual, expected) + # Make consistent with test_interval_new.py (see #16316, #16386) + @pytest.mark.parametrize('item', [ + [3], np.arange(1, 5), [Interval(1, 4)], interval_range(1, 4)]) + def test_get_indexer_length_one(self, item, closed): + # GH 17284 + index = IntervalIndex.from_tuples([(0, 5)], closed=closed) + result = index.get_indexer(item) + expected = np.array([0] * len(item), dtype='intp') + tm.assert_numpy_array_equal(result, expected) + # To be removed, replaced by test_interval_new.py (see #16316, #16386) def test_contains(self): # Only endpoints are valid.