Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 108 additions & 5 deletions pandas/core/indexes/range.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
from pandas.compat.numpy import function as nv
from pandas.util._decorators import (
cache_readonly,
doc,
set_module,
)

Expand Down Expand Up @@ -473,8 +472,51 @@ def inferred_type(self) -> str:
# --------------------------------------------------------------------
# Indexing Methods

@doc(Index.get_loc)
def get_loc(self, key) -> int:
"""
Get integer location for requested label.

Parameters
----------
key : int or float
Label to locate. Integer-like floats (e.g. 3.0) are accepted and
treated as the corresponding integer. Non-integer floats and other
non-integer labels are not valid and will raise KeyError or
InvalidIndexError.

Returns
-------
int
Integer location of the label within the RangeIndex.

Raises
------
KeyError
If the label is not present in the RangeIndex or the label is a
non-integer value.
InvalidIndexError
If the label is of an invalid type for the RangeIndex.

See Also
--------
RangeIndex.get_slice_bound : Calculate slice bound that corresponds to
given label.
RangeIndex.get_indexer : Computes indexer and mask for new index given
the current index.
RangeIndex.get_non_unique : Returns indexer and masks for new index given
the current index.
RangeIndex.get_indexer_for : Returns an indexer even when non-unique.

Examples
--------
>>> idx = pd.RangeIndex(5)
>>> idx.get_loc(3)
3

>>> idx = pd.RangeIndex(2, 10, 2) # values [2, 4, 6, 8]
>>> idx.get_loc(6)
2
"""
if is_integer(key) or (is_float(key) and key.is_integer()):
new_key = int(key)
try:
Expand Down Expand Up @@ -528,12 +570,39 @@ def _should_fallback_to_positional(self) -> bool:
def tolist(self) -> list[int]:
return list(self._range)

@doc(Index.__iter__)
def __iter__(self) -> Iterator[int]:
"""
Return an iterator of the values.

Returns
-------
iterator
An iterator yielding ints from the RangeIndex.

Examples
--------
>>> idx = pd.RangeIndex(3)
>>> for x in idx:
... print(x)
0
1
2
"""
yield from self._range

@doc(Index._shallow_copy)
def _shallow_copy(self, values, name: Hashable = no_default):
"""
Create a new RangeIndex with the same class as the caller, don't copy the
data, use the same object attributes with passed in attributes taking
precedence.

*this is an internal non-public method*

Parameters
----------
values : the values to create the new RangeIndex, optional
name : Label, defaults to self.name
"""
name = self._name if name is no_default else name

if values.dtype.kind == "f":
Expand All @@ -560,8 +629,42 @@ def _wrap_reindex_result(self, target, indexer, preserve_names: bool):
target = self._shallow_copy(target._values, name=target.name)
return super()._wrap_reindex_result(target, indexer, preserve_names)

@doc(Index.copy)
def copy(self, name: Hashable | None = None, deep: bool = False) -> Self:
"""
Make a copy of this object.

Name is set on the new object.

Parameters
----------
name : Label, optional
Set name for new object.
deep : bool, default False
If True attempts to make a deep copy of the RangeIndex.
Else makes a shallow copy.

Returns
-------
RangeIndex
RangeIndex refer to new object which is a copy of this object.

See Also
--------
RangeIndex.delete: Make new RangeIndex with passed location(-s) deleted.
RangeIndex.drop: Make new RangeIndex with passed list of labels deleted.

Notes
-----
In most cases, there should be no functional difference from using
``deep``, but if ``deep`` is passed it will attempt to deepcopy.

Examples
--------
>>> idx = pd.RangeIndex(3)
>>> new_idx = idx.copy()
>>> idx is new_idx
False
"""
name = self._validate_names(name=name, deep=deep)[0]
new_index = self._rename(name=name)
return new_index
Expand Down
Loading