diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py index 457ec8ab702d5..f586495531a41 100644 --- a/pandas/core/indexes/base.py +++ b/pandas/core/indexes/base.py @@ -3428,7 +3428,7 @@ def get_indexer( ) -> np.ndarray: # returned ndarray is np.intp method = missing.clean_reindex_fill_method(method) - target = ensure_index(target) + target = self._maybe_cast_listlike_indexer(target) self._check_indexing_method(method) @@ -5678,6 +5678,12 @@ def _maybe_cast_indexer(self, key): return com.cast_scalar_indexer(key) return key + def _maybe_cast_listlike_indexer(self, target) -> Index: + """ + Analogue to maybe_cast_indexer for get_indexer instead of get_loc. + """ + return ensure_index(target) + @final def _validate_indexer(self, form: str_t, key, kind: str_t): """ diff --git a/pandas/core/indexes/datetimelike.py b/pandas/core/indexes/datetimelike.py index 3dc46f04d1d45..8d9b2cdd953e8 100644 --- a/pandas/core/indexes/datetimelike.py +++ b/pandas/core/indexes/datetimelike.py @@ -49,6 +49,7 @@ TimedeltaArray, ) from pandas.core.arrays.datetimelike import DatetimeLikeArrayMixin +import pandas.core.common as com import pandas.core.indexes.base as ibase from pandas.core.indexes.base import ( Index, @@ -593,12 +594,13 @@ def _from_join_target(self, result: np.ndarray): # -------------------------------------------------------------------- - @doc(Index._convert_arr_indexer) - def _convert_arr_indexer(self, keyarr): + @doc(Index._maybe_cast_listlike_indexer) + def _maybe_cast_listlike_indexer(self, keyarr): try: - return self._data._validate_listlike(keyarr, allow_object=True) + res = self._data._validate_listlike(keyarr, allow_object=True) except (ValueError, TypeError): - return super()._convert_arr_indexer(keyarr) + res = com.asarray_tuplesafe(keyarr) + return Index(res, dtype=res.dtype) class DatetimeTimedeltaMixin(DatetimeIndexOpsMixin): diff --git a/pandas/core/indexing.py b/pandas/core/indexing.py index 66de374121fb0..4f55459040bc0 100644 --- a/pandas/core/indexing.py +++ b/pandas/core/indexing.py @@ -30,6 +30,7 @@ is_object_dtype, is_scalar, is_sequence, + needs_i8_conversion, ) from pandas.core.dtypes.concat import concat_compat from pandas.core.dtypes.generic import ( @@ -1301,10 +1302,19 @@ def _get_listlike_indexer(self, key, axis: int): self._validate_read_indexer(keyarr, indexer, axis) - if isinstance(ax, (IntervalIndex, CategoricalIndex)): - # take instead of reindex to preserve dtype. For IntervalIndex - # this is to map integers to the Intervals they match to. + if needs_i8_conversion(ax.dtype) or isinstance( + ax, (IntervalIndex, CategoricalIndex) + ): + # For CategoricalIndex take instead of reindex to preserve dtype. + # For IntervalIndex this is to map integers to the Intervals they match to. keyarr = ax.take(indexer) + if keyarr.dtype.kind in ["m", "M"]: + # DTI/TDI.take can infer a freq in some cases when we dont want one + if isinstance(key, list) or ( + isinstance(key, type(ax)) and key.freq is None + ): + keyarr = keyarr._with_freq(None) + return keyarr, indexer def _validate_read_indexer(self, key, indexer, axis: int): diff --git a/pandas/tests/indexing/test_indexing.py b/pandas/tests/indexing/test_indexing.py index 9c6a39c991912..425c68725c595 100644 --- a/pandas/tests/indexing/test_indexing.py +++ b/pandas/tests/indexing/test_indexing.py @@ -94,6 +94,8 @@ def test_getitem_ndarray_3d( msgs.append("Index data must be 1-dimensional") if isinstance(index, pd.IntervalIndex) and indexer_sli is tm.iloc: msgs.append("Index data must be 1-dimensional") + if isinstance(index, (pd.TimedeltaIndex, pd.DatetimeIndex, pd.PeriodIndex)): + msgs.append("Data must be 1-dimensional") if len(index) == 0 or isinstance(index, pd.MultiIndex): msgs.append("positional indexers are out-of-bounds") msg = "|".join(msgs) @@ -127,6 +129,7 @@ def test_setitem_ndarray_3d(self, index, frame_or_series, indexer_sli): r"Buffer has wrong number of dimensions \(expected 1, got 3\)", "Cannot set values with ndim > 1", "Index data must be 1-dimensional", + "Data must be 1-dimensional", "Array conditional must be same shape as self", ] )