Skip to content

Commit c877772

Browse files
toobazjbrockmendel
authored andcommitted
BUG: intersection of decreasing RangeIndexes (pandas-dev#17374)
closes pandas-dev#17296
1 parent 991af8f commit c877772

File tree

3 files changed

+29
-9
lines changed

3 files changed

+29
-9
lines changed

doc/source/whatsnew/v0.21.0.txt

+1
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,7 @@ Indexing
417417
- Bug in ``.iloc`` when used with inplace addition or assignment and an int indexer on a ``MultiIndex`` causing the wrong indexes to be read from and written to (:issue:`17148`)
418418
- Bug in ``.isin()`` in which checking membership in empty ``Series`` objects raised an error (:issue:`16991`)
419419
- Bug in ``CategoricalIndex`` reindexing in which specified indices containing duplicates were not being respected (:issue:`17323`)
420+
- Bug in intersection of ``RangeIndex`` with negative step (:issue:`17296`)
420421

421422
I/O
422423
^^^

pandas/core/indexes/range.py

+13-9
Original file line numberDiff line numberDiff line change
@@ -324,34 +324,38 @@ def intersection(self, other):
324324
if not len(self) or not len(other):
325325
return RangeIndex._simple_new(None)
326326

327+
first = self[::-1] if self._step < 0 else self
328+
second = other[::-1] if other._step < 0 else other
329+
327330
# check whether intervals intersect
328331
# deals with in- and decreasing ranges
329-
int_low = max(min(self._start, self._stop + 1),
330-
min(other._start, other._stop + 1))
331-
int_high = min(max(self._stop, self._start + 1),
332-
max(other._stop, other._start + 1))
332+
int_low = max(first._start, second._start)
333+
int_high = min(first._stop, second._stop)
333334
if int_high <= int_low:
334335
return RangeIndex._simple_new(None)
335336

336337
# Method hint: linear Diophantine equation
337338
# solve intersection problem
338339
# performance hint: for identical step sizes, could use
339340
# cheaper alternative
340-
gcd, s, t = self._extended_gcd(self._step, other._step)
341+
gcd, s, t = first._extended_gcd(first._step, second._step)
341342

342343
# check whether element sets intersect
343-
if (self._start - other._start) % gcd:
344+
if (first._start - second._start) % gcd:
344345
return RangeIndex._simple_new(None)
345346

346347
# calculate parameters for the RangeIndex describing the
347348
# intersection disregarding the lower bounds
348-
tmp_start = self._start + (other._start - self._start) * \
349-
self._step // gcd * s
350-
new_step = self._step * other._step // gcd
349+
tmp_start = first._start + (second._start - first._start) * \
350+
first._step // gcd * s
351+
new_step = first._step * second._step // gcd
351352
new_index = RangeIndex(tmp_start, int_high, new_step, fastpath=True)
352353

353354
# adjust index to limiting interval
354355
new_index._start = new_index._min_fitting_element(int_low)
356+
357+
if (self._step < 0 and other._step < 0) is not (new_index._step < 0):
358+
new_index = new_index[::-1]
355359
return new_index
356360

357361
def _min_fitting_element(self, lower_limit):

pandas/tests/indexes/test_range.py

+15
Original file line numberDiff line numberDiff line change
@@ -610,6 +610,21 @@ def test_intersection(self):
610610
other.values)))
611611
tm.assert_index_equal(result, expected)
612612

613+
# reversed (GH 17296)
614+
result = other.intersection(self.index)
615+
tm.assert_index_equal(result, expected)
616+
617+
# GH 17296: intersect two decreasing RangeIndexes
618+
first = RangeIndex(10, -2, -2)
619+
other = RangeIndex(5, -4, -1)
620+
expected = first.astype(int).intersection(other.astype(int))
621+
result = first.intersection(other).astype(int)
622+
tm.assert_index_equal(result, expected)
623+
624+
# reversed
625+
result = other.intersection(first).astype(int)
626+
tm.assert_index_equal(result, expected)
627+
613628
index = RangeIndex(5)
614629

615630
# intersect of non-overlapping indices

0 commit comments

Comments
 (0)