diff --git a/doc/source/whatsnew/v2.0.0.rst b/doc/source/whatsnew/v2.0.0.rst index d8609737b8c7a..451cba732ff60 100644 --- a/doc/source/whatsnew/v2.0.0.rst +++ b/doc/source/whatsnew/v2.0.0.rst @@ -698,7 +698,7 @@ Strings Interval ^^^^^^^^ -- +- Bug in :meth:`IntervalIndex.is_overlapping` incorrect output if interval has duplicate left boundaries (:issue:`49581`) - Indexing diff --git a/pandas/_libs/intervaltree.pxi.in b/pandas/_libs/intervaltree.pxi.in index e7a310513d2fa..0d7c96a6f2f2b 100644 --- a/pandas/_libs/intervaltree.pxi.in +++ b/pandas/_libs/intervaltree.pxi.in @@ -81,7 +81,8 @@ cdef class IntervalTree(IntervalMixin): """How to sort the left labels; this is used for binary search """ if self._left_sorter is None: - self._left_sorter = np.argsort(self.left) + values = [self.right, self.left] + self._left_sorter = np.lexsort(values) return self._left_sorter @property diff --git a/pandas/tests/indexes/interval/test_interval.py b/pandas/tests/indexes/interval/test_interval.py index c8d7470032e5f..98c21fad1f8c2 100644 --- a/pandas/tests/indexes/interval/test_interval.py +++ b/pandas/tests/indexes/interval/test_interval.py @@ -791,6 +791,13 @@ def test_is_overlapping(self, start, shift, na_value, closed): result = index.is_overlapping assert result is expected + # intervals with duplicate left values + a = [10, 15, 20, 25, 30, 35, 40, 45, 45, 50, 55, 60, 65, 70, 75, 80, 85] + b = [15, 20, 25, 30, 35, 40, 45, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90] + index = IntervalIndex.from_arrays(a, b, closed="right") + result = index.is_overlapping + assert result is False + @pytest.mark.parametrize( "tuples", [