Skip to content

Commit b87edc7

Browse files
mroeschkepmhatre1
authored andcommitted
PERF: Allow RangeIndex.take to return a RangeIndex when possible (pandas-dev#57445)
1 parent 22ac90b commit b87edc7

File tree

3 files changed

+25
-6
lines changed

3 files changed

+25
-6
lines changed

doc/source/whatsnew/v3.0.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ Performance improvements
167167
- Performance improvement in :meth:`Index.take` when ``indices`` is a full range indexer from zero to length of index (:issue:`56806`)
168168
- Performance improvement in :meth:`MultiIndex.equals` for equal length indexes (:issue:`56990`)
169169
- Performance improvement in :meth:`RangeIndex.append` when appending the same index (:issue:`57252`)
170+
- Performance improvement in :meth:`RangeIndex.take` returning a :class:`RangeIndex` instead of a :class:`Index` when possible. (:issue:`57445`)
170171
- Performance improvement in indexing operations for string dtypes (:issue:`56997`)
171172
-
172173

pandas/core/indexes/range.py

+7-6
Original file line numberDiff line numberDiff line change
@@ -1006,11 +1006,13 @@ def _concat(self, indexes: list[Index], name: Hashable) -> Index:
10061006
# Get the stop value from "next" or alternatively
10071007
# from the last non-empty index
10081008
stop = non_empty_indexes[-1].stop if next_ is None else next_
1009-
return RangeIndex(start, stop, step).rename(name)
1009+
if len(non_empty_indexes) == 1:
1010+
step = non_empty_indexes[0].step
1011+
return RangeIndex(start, stop, step, name=name)
10101012

10111013
# Here all "indexes" had 0 length, i.e. were empty.
10121014
# In this case return an empty range index.
1013-
return RangeIndex(0, 0).rename(name)
1015+
return RangeIndex(_empty_range, name=name)
10141016

10151017
def __len__(self) -> int:
10161018
"""
@@ -1168,7 +1170,7 @@ def take( # type: ignore[override]
11681170
allow_fill: bool = True,
11691171
fill_value=None,
11701172
**kwargs,
1171-
) -> Index:
1173+
) -> Self | Index:
11721174
if kwargs:
11731175
nv.validate_take((), kwargs)
11741176
if is_scalar(indices):
@@ -1179,7 +1181,7 @@ def take( # type: ignore[override]
11791181
self._maybe_disallow_fill(allow_fill, fill_value, indices)
11801182

11811183
if len(indices) == 0:
1182-
taken = np.array([], dtype=self.dtype)
1184+
return type(self)(_empty_range, name=self.name)
11831185
else:
11841186
ind_max = indices.max()
11851187
if ind_max >= len(self):
@@ -1199,5 +1201,4 @@ def take( # type: ignore[override]
11991201
if self.start != 0:
12001202
taken += self.start
12011203

1202-
# _constructor so RangeIndex-> Index with an int64 dtype
1203-
return self._constructor._simple_new(taken, name=self.name)
1204+
return self._shallow_copy(taken, name=self.name)

pandas/tests/indexes/ranges/test_range.py

+17
Original file line numberDiff line numberDiff line change
@@ -606,3 +606,20 @@ def test_range_index_rsub_by_const(self):
606606
result = 3 - RangeIndex(0, 4, 1)
607607
expected = RangeIndex(3, -1, -1)
608608
tm.assert_index_equal(result, expected)
609+
610+
611+
def test_take_return_rangeindex():
612+
ri = RangeIndex(5, name="foo")
613+
result = ri.take([])
614+
expected = RangeIndex(0, name="foo")
615+
tm.assert_index_equal(result, expected, exact=True)
616+
617+
result = ri.take([3, 4])
618+
expected = RangeIndex(3, 5, name="foo")
619+
tm.assert_index_equal(result, expected, exact=True)
620+
621+
622+
def test_append_one_nonempty_preserve_step():
623+
expected = RangeIndex(0, -1, -1)
624+
result = RangeIndex(0).append([expected])
625+
tm.assert_index_equal(result, expected, exact=True)

0 commit comments

Comments
 (0)