diff --git a/pandas/core/indexes/multi.py b/pandas/core/indexes/multi.py index 8903d29782610..d007964a7b266 100644 --- a/pandas/core/indexes/multi.py +++ b/pandas/core/indexes/multi.py @@ -73,7 +73,6 @@ from pandas.core.arrays import Categorical from pandas.core.arrays.categorical import factorize_from_iterables import pandas.core.common as com -from pandas.core.indexers import is_empty_indexer import pandas.core.indexes.base as ibase from pandas.core.indexes.base import ( Index, @@ -2559,24 +2558,29 @@ def _convert_listlike_indexer(self, keyarr) -> np.ndarray | None: # are we indexing a specific 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), dtype=np.intp) - return indexer - - check = self.levels[0].get_indexer(keyarr) - mask = check == -1 + indexer = self._get_indexer_level_0(keyarr) + mask = indexer == -1 if mask.any(): - raise KeyError(f"{keyarr[mask]} not in index") - elif is_empty_indexer(indexer, keyarr): + check = self.levels[0].get_indexer(keyarr) + cmask = check == -1 + if cmask.any(): + raise KeyError(f"{keyarr[cmask]} not in index") # We get here when levels still contain values which are not # actually in Index anymore raise KeyError(f"{keyarr} not in index") return indexer + def _get_indexer_level_0(self, target) -> np.ndarray: + """ + Optimized equivalent to `self.get_level_values(0).get_indexer_for(target)`. + """ + lev = self.levels[0] + codes = self._codes[0] + cat = Categorical.from_codes(codes=codes, categories=lev) + ci = Index(cat) + return ci.get_indexer_for(target) + def _get_partial_string_timestamp_match_key(self, key): """ Translate any partial string timestamp matches in key, returning the