Skip to content

Commit 7590b87

Browse files
author
tp
committed
add IntervalIndex.get_loc_exact
1 parent b835127 commit 7590b87

File tree

4 files changed

+66
-6
lines changed

4 files changed

+66
-6
lines changed

doc/source/whatsnew/v0.23.0.txt

+1
Original file line numberDiff line numberDiff line change
@@ -507,6 +507,7 @@ Other API Changes
507507
- Set operations (union, difference...) on :class:`IntervalIndex` with incompatible index types will now raise a ``TypeError`` rather than a ``ValueError`` (:issue:`19329`)
508508
- :class:`DateOffset` objects render more simply, e.g. "<DateOffset: days=1>" instead of "<DateOffset: kwds={'days': 1}>" (:issue:`19403`)
509509
- :func:`pandas.merge` provides a more informative error message when trying to merge on timezone-aware and timezone-naive columns (:issue:`15800`)
510+
- New :meth:`IntervalIndex.get_loc_exact` has been added to find exact Interval matches only (:issue:`19349`)
510511

511512
.. _whatsnew_0230.deprecations:
512513

pandas/core/indexes/interval.py

+47-5
Original file line numberDiff line numberDiff line change
@@ -903,11 +903,8 @@ def _get_loc_only_exact_matches(self, key):
903903
if not self.is_unique:
904904
raise ValueError("cannot index with a slice Interval"
905905
" and a non-unique index")
906-
907-
# TODO: this expands to a tuple index, see if we can
908-
# do better
909-
return Index(self._multiindex.values).get_loc(key)
910-
raise KeyError
906+
return super(IntervalIndex, self)._engine.get_loc(key)
907+
raise KeyError(key)
911908

912909
def _find_non_overlapping_monotonic_bounds(self, key):
913910
if isinstance(key, IntervalMixin):
@@ -970,6 +967,10 @@ def get_loc(self, key, method=None):
970967
>>> overlapping_index = pd.IntervalIndex([i2, i3])
971968
>>> overlapping_index.get_loc(1.5)
972969
array([0, 1], dtype=int64)
970+
971+
See Also
972+
--------
973+
get_loc_exact : Exact matches only
973974
"""
974975
self._check_method(method)
975976

@@ -1003,6 +1004,47 @@ def get_loc(self, key, method=None):
10031004
else:
10041005
return self._engine.get_loc(key)
10051006

1007+
def get_loc_exact(self, key, method=None):
1008+
"""Get integer location, slice or boolean mask for exact
1009+
Interval matches only.
1010+
1011+
Parameters
1012+
----------
1013+
key : Interval
1014+
The label we want to find locations for. Must have type
1015+
:class:`Interval`
1016+
method : {None}, optional
1017+
* default: matches where the label exactly matches a given
1018+
:class:`Interval`.
1019+
1020+
Returns
1021+
-------
1022+
loc : int if unique index, slice if monotonic index, else mask
1023+
1024+
Examples
1025+
---------
1026+
>>> i1, i2 = pd.Interval(0, 1), pd.Interval(1, 2)
1027+
>>> index = pd.IntervalIndex([i1, i2])
1028+
>>> index.get_loc_exact(i1)
1029+
0
1030+
1031+
If an exact match is not found, a KeyError is raised
1032+
>>> index.get_loc_exact(pd.Interval(0.5, 1.5))
1033+
KeyError: Interval(0.5, 1.5, closed='right')
1034+
1035+
If a label is in several locations, you get all the relevant
1036+
locations.
1037+
1038+
>>> index = pd.IntervalIndex([i1, i2, i1])
1039+
>>> index.get_loc_exact(i1)
1040+
array([ True, False, True], dtype=bool)
1041+
1042+
See Also
1043+
--------
1044+
get_loc
1045+
"""
1046+
return self.astype(object).get_loc(key, method=method)
1047+
10061048
def get_value(self, series, key):
10071049
if com.is_bool_indexer(key):
10081050
loc = key

pandas/tests/indexes/interval/test_interval.py

+17
Original file line numberDiff line numberDiff line change
@@ -497,6 +497,23 @@ def test_get_loc_interval(self):
497497
pytest.raises(KeyError, self.index.get_loc,
498498
Interval(-1, 0, 'left'))
499499

500+
# To be removed, replaced by test_interval_new.py (see #16316, #16386)
501+
def test_get_loc_exact(self):
502+
# GH19353
503+
assert self.index.get_loc_exact(Interval(0, 1)) == 0
504+
with pytest.raises(KeyError):
505+
self.index.get_loc_exact(1)
506+
with pytest.raises(KeyError):
507+
self.index.get_loc_exact(Interval(0, 1, 'left'))
508+
with pytest.raises(KeyError):
509+
self.index.get_loc_exact(Interval(0, 0.5))
510+
with pytest.raises(KeyError):
511+
self.index.get_loc_exact(Interval(2, 3))
512+
with pytest.raises(KeyError):
513+
self.index.get_loc_exact(Interval(-1, 0, 'left'))
514+
# See #19353#issuecomment-364295029
515+
self.index.get_loc(Interval(0, 1))
516+
500517
# To be removed, replaced by test_interval_new.py (see #16316, #16386)
501518
def test_get_indexer(self):
502519
actual = self.index.get_indexer([-1, 0, 0.5, 1, 1.5, 2, 3])

pandas/tests/indexing/interval/test_interval.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ def test_with_slices(self):
136136
s[Interval(3, 6):]
137137

138138
expected = s.iloc[3:5]
139-
result = s[[Interval(3, 6)]]
139+
result = s[Interval(3, 6)]
140140
tm.assert_series_equal(expected, result)
141141

142142
# slice of scalar with step != 1

0 commit comments

Comments
 (0)