diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py index 802fd0feedb48..e076bc77f91f0 100644 --- a/pandas/core/indexes/base.py +++ b/pandas/core/indexes/base.py @@ -3684,43 +3684,6 @@ def is_int(v): return indexer - def _convert_listlike_indexer(self, keyarr): - """ - Parameters - ---------- - keyarr : list-like - Indexer to convert. - - Returns - ------- - indexer : numpy.ndarray or None - Return an ndarray or None if cannot convert. - keyarr : numpy.ndarray - Return tuple-safe keys. - """ - if isinstance(keyarr, Index): - pass - else: - keyarr = self._convert_arr_indexer(keyarr) - - indexer = None - return indexer, keyarr - - def _convert_arr_indexer(self, keyarr) -> np.ndarray: - """ - Convert an array-like indexer to the appropriate dtype. - - Parameters - ---------- - keyarr : array-like - Indexer to convert. - - Returns - ------- - converted_keyarr : array-like - """ - return com.asarray_tuplesafe(keyarr) - @final def _invalid_indexer(self, form: str_t, key) -> TypeError: """ diff --git a/pandas/core/indexes/multi.py b/pandas/core/indexes/multi.py index 07795a9f09c2a..06291fb5c3c0c 100644 --- a/pandas/core/indexes/multi.py +++ b/pandas/core/indexes/multi.py @@ -2581,29 +2581,29 @@ def _get_values_for_loc(self, series: Series, loc, key): new_ser = series._constructor(new_values, index=new_index, name=series.name) return new_ser.__finalize__(series) - def _convert_listlike_indexer(self, keyarr): + def _convert_listlike_indexer(self, keyarr) -> np.ndarray | None: """ + Analogous to get_indexer when we are partial-indexing on our first level. + Parameters ---------- - keyarr : list-like + keyarr : Index, np.ndarray, or ExtensionArray Indexer to convert. Returns ------- - tuple (indexer, keyarr) - indexer is an ndarray or None if cannot convert - keyarr are tuple-safe keys + np.ndarray[intp] or None """ - indexer, keyarr = super()._convert_listlike_indexer(keyarr) + indexer = None # are we indexing a specific level - if indexer is None and len(keyarr) and not isinstance(keyarr[0], tuple): - level = 0 - _, indexer = self.reindex(keyarr, level=level) + if len(keyarr) and not isinstance(keyarr[0], tuple): + _, indexer = self.reindex(keyarr, level=0) # take all if indexer is None: - indexer = np.arange(len(self)) + indexer = np.arange(len(self), dtype=np.intp) + return indexer check = self.levels[0].get_indexer(keyarr) mask = check == -1 @@ -2614,7 +2614,7 @@ def _convert_listlike_indexer(self, keyarr): # actually in Index anymore raise KeyError(f"{keyarr} not in index") - return indexer, keyarr + return indexer def _get_partial_string_timestamp_match_key(self, key): """ diff --git a/pandas/core/indexing.py b/pandas/core/indexing.py index 4f55459040bc0..3707e141bc447 100644 --- a/pandas/core/indexing.py +++ b/pandas/core/indexing.py @@ -1286,13 +1286,21 @@ def _get_listlike_indexer(self, key, axis: int): """ ax = self.obj._get_axis(axis) - # Have the index compute an indexer or return None - # if it cannot handle: - indexer, keyarr = ax._convert_listlike_indexer(key) - # We only act on all found values: - if indexer is not None and (indexer != -1).all(): - # _validate_read_indexer is a no-op if no -1s, so skip - return ax[indexer], indexer + keyarr = key + if not isinstance(keyarr, Index): + keyarr = com.asarray_tuplesafe(keyarr) + + if isinstance(ax, MultiIndex): + # get_indexer expects a MultiIndex or sequence of tuples, but + # we may be doing partial-indexing, so need an extra check + + # Have the index compute an indexer or return None + # if it cannot handle: + indexer = ax._convert_listlike_indexer(keyarr) + # We only act on all found values: + if indexer is not None and (indexer != -1).all(): + # _validate_read_indexer is a no-op if no -1s, so skip + return ax[indexer], indexer if ax._index_as_unique: indexer = ax.get_indexer_for(keyarr)