From 7eb1769e988bed59a41ed09eb3bee568d1eedc85 Mon Sep 17 00:00:00 2001 From: Brock Date: Tue, 19 Oct 2021 15:23:02 -0700 Subject: [PATCH 1/2] BUG: RangeIndex.difference missed case --- pandas/core/indexes/range.py | 4 ++++ pandas/tests/indexes/ranges/test_setops.py | 9 +++++++++ 2 files changed, 13 insertions(+) diff --git a/pandas/core/indexes/range.py b/pandas/core/indexes/range.py index 4def2e4b93553..d44714400a47b 100644 --- a/pandas/core/indexes/range.py +++ b/pandas/core/indexes/range.py @@ -712,6 +712,10 @@ def _difference(self, other, sort=None): elif overlap[-1] == first[-1]: # The difference is everything before the intersection new_rng = range(first.start, overlap[0], first.step) + elif overlap._range == first[1:-1]: + # e.g. range(4) and range(1, 3) + step = len(first) - 1 + new_rng = first[::step] else: # The difference is not range-like # e.g. range(1, 10, 1) and range(3, 7, 1) diff --git a/pandas/tests/indexes/ranges/test_setops.py b/pandas/tests/indexes/ranges/test_setops.py index 583391bd96a85..c5a6064b90259 100644 --- a/pandas/tests/indexes/ranges/test_setops.py +++ b/pandas/tests/indexes/ranges/test_setops.py @@ -377,6 +377,15 @@ def test_difference_mismatched_step(self): result = obj[::-1].difference(obj[1::2], sort=False) tm.assert_index_equal(result, expected[::-1], exact=True) + def test_difference_interior_overlap_endpoints_preserved(self): + left = RangeIndex(range(4)) + right = RangeIndex(range(1, 3)) + + result = left.difference(right) + expected = RangeIndex(0, 4, 3) + assert expected.tolist() == [0, 3] + tm.assert_index_equal(result, expected, exact=True) + def test_difference_interior_non_preserving(self): # case with intersection of length 1 but RangeIndex is not preserved idx = Index(range(10)) From 453858a16718836708760929953087c9a9a1bc96 Mon Sep 17 00:00:00 2001 From: Brock Date: Tue, 19 Oct 2021 18:59:01 -0700 Subject: [PATCH 2/2] BUG: missed RangeIndex.difference cases --- pandas/core/indexes/range.py | 17 ++++++++++++----- pandas/tests/indexes/ranges/test_setops.py | 9 +++++++++ 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/pandas/core/indexes/range.py b/pandas/core/indexes/range.py index d44714400a47b..b209a6556709b 100644 --- a/pandas/core/indexes/range.py +++ b/pandas/core/indexes/range.py @@ -705,6 +705,10 @@ def _difference(self, other, sort=None): else: return super()._difference(other, sort=sort) + elif len(overlap) == 2 and overlap[0] == first[0] and overlap[-1] == first[-1]: + # e.g. range(-8, 20, 7) and range(13, -9, -3) + return self[1:-1] + if overlap.step == first.step: if overlap[0] == first.start: # The difference is everything after the intersection @@ -729,16 +733,19 @@ def _difference(self, other, sort=None): if overlap.step == first.step * 2: if overlap[0] == first[0] and overlap[-1] in (first[-1], first[-2]): # e.g. range(1, 10, 1) and range(1, 10, 2) - return self[1::2] + new_rng = first[1::2] elif overlap[0] == first[1] and overlap[-1] in (first[-1], first[-2]): # e.g. range(1, 10, 1) and range(2, 10, 2) - return self[::2] + new_rng = first[::2] - # We can get here with e.g. range(20) and range(0, 10, 2) + else: + # We can get here with e.g. range(20) and range(0, 10, 2) + return super()._difference(other, sort=sort) - # e.g. range(10) and range(0, 10, 3) - return super()._difference(other, sort=sort) + else: + # e.g. range(10) and range(0, 10, 3) + return super()._difference(other, sort=sort) new_index = type(self)._simple_new(new_rng, name=res_name) if first is not self._range: diff --git a/pandas/tests/indexes/ranges/test_setops.py b/pandas/tests/indexes/ranges/test_setops.py index c5a6064b90259..2942010af2720 100644 --- a/pandas/tests/indexes/ranges/test_setops.py +++ b/pandas/tests/indexes/ranges/test_setops.py @@ -386,6 +386,15 @@ def test_difference_interior_overlap_endpoints_preserved(self): assert expected.tolist() == [0, 3] tm.assert_index_equal(result, expected, exact=True) + def test_difference_endpoints_overlap_interior_preserved(self): + left = RangeIndex(-8, 20, 7) + right = RangeIndex(13, -9, -3) + + result = left.difference(right) + expected = RangeIndex(-1, 13, 7) + assert expected.tolist() == [-1, 6] + tm.assert_index_equal(result, expected, exact=True) + def test_difference_interior_non_preserving(self): # case with intersection of length 1 but RangeIndex is not preserved idx = Index(range(10))