diff --git a/doc/source/whatsnew/v3.0.0.rst b/doc/source/whatsnew/v3.0.0.rst index e17d5b0cf8edb..8c793a02ada86 100644 --- a/doc/source/whatsnew/v3.0.0.rst +++ b/doc/source/whatsnew/v3.0.0.rst @@ -275,6 +275,7 @@ Performance improvements - Performance improvement in :meth:`RangeIndex.__getitem__` with a boolean mask or integers returning a :class:`RangeIndex` instead of a :class:`Index` when possible. (:issue:`57588`) - Performance improvement in :meth:`RangeIndex.append` when appending the same index (:issue:`57252`) - Performance improvement in :meth:`RangeIndex.argmin` and :meth:`RangeIndex.argmax` (:issue:`57823`) +- Performance improvement in :meth:`RangeIndex.insert` returning a :class:`RangeIndex` instead of a :class:`Index` when the :class:`RangeIndex` is empty. (:issue:`57833`) - Performance improvement in :meth:`RangeIndex.round` returning a :class:`RangeIndex` instead of a :class:`Index` when possible. (:issue:`57824`) - Performance improvement in :meth:`RangeIndex.join` returning a :class:`RangeIndex` instead of a :class:`Index` when possible. (:issue:`57651`, :issue:`57752`) - Performance improvement in :meth:`RangeIndex.reindex` returning a :class:`RangeIndex` instead of a :class:`Index` when possible. (:issue:`57647`, :issue:`57752`) diff --git a/pandas/core/indexes/range.py b/pandas/core/indexes/range.py index e5e0a4b66f71b..99b4d5a764c46 100644 --- a/pandas/core/indexes/range.py +++ b/pandas/core/indexes/range.py @@ -396,7 +396,7 @@ def __contains__(self, key: Any) -> bool: hash(key) try: key = ensure_python_int(key) - except TypeError: + except (TypeError, OverflowError): return False return key in self._range @@ -1009,23 +1009,27 @@ def delete(self, loc) -> Index: # type: ignore[override] return super().delete(loc) def insert(self, loc: int, item) -> Index: - if len(self) and (is_integer(item) or is_float(item)): + if is_integer(item) or is_float(item): # We can retain RangeIndex is inserting at the beginning or end, # or right in the middle. - rng = self._range - if loc == 0 and item == self[0] - self.step: - new_rng = range(rng.start - rng.step, rng.stop, rng.step) - return type(self)._simple_new(new_rng, name=self._name) - - elif loc == len(self) and item == self[-1] + self.step: - new_rng = range(rng.start, rng.stop + rng.step, rng.step) - return type(self)._simple_new(new_rng, name=self._name) - - elif len(self) == 2 and item == self[0] + self.step / 2: - # e.g. inserting 1 into [0, 2] - step = int(self.step / 2) - new_rng = range(self.start, self.stop, step) + if len(self) == 0 and loc == 0 and is_integer(item): + new_rng = range(item, item + self.step, self.step) return type(self)._simple_new(new_rng, name=self._name) + elif len(self): + rng = self._range + if loc == 0 and item == self[0] - self.step: + new_rng = range(rng.start - rng.step, rng.stop, rng.step) + return type(self)._simple_new(new_rng, name=self._name) + + elif loc == len(self) and item == self[-1] + self.step: + new_rng = range(rng.start, rng.stop + rng.step, rng.step) + return type(self)._simple_new(new_rng, name=self._name) + + elif len(self) == 2 and item == self[0] + self.step / 2: + # e.g. inserting 1 into [0, 2] + step = int(self.step / 2) + new_rng = range(self.start, self.stop, step) + return type(self)._simple_new(new_rng, name=self._name) return super().insert(loc, item) diff --git a/pandas/tests/indexes/ranges/test_range.py b/pandas/tests/indexes/ranges/test_range.py index 00655f5546df8..621f405793e02 100644 --- a/pandas/tests/indexes/ranges/test_range.py +++ b/pandas/tests/indexes/ranges/test_range.py @@ -659,6 +659,13 @@ def test_reindex_empty_returns_rangeindex(): tm.assert_numpy_array_equal(result_indexer, expected_indexer) +def test_insert_empty_0_loc(): + ri = RangeIndex(0, step=10, name="foo") + result = ri.insert(0, 5) + expected = RangeIndex(5, 15, 10, name="foo") + tm.assert_index_equal(result, expected, exact=True) + + def test_append_non_rangeindex_return_rangeindex(): ri = RangeIndex(1) result = ri.append(Index([1]))