Skip to content

Commit f463224

Browse files
authored
REF: de-duplicate MultiIndex.reindex (pandas-dev#42226)
1 parent e4189e2 commit f463224

File tree

2 files changed

+33
-53
lines changed

2 files changed

+33
-53
lines changed

pandas/core/indexes/base.py

+25-5
Original file line numberDiff line numberDiff line change
@@ -3781,14 +3781,25 @@ def reindex(
37813781
target = ensure_has_len(target) # target may be an iterator
37823782

37833783
if not isinstance(target, Index) and len(target) == 0:
3784-
target = self[:0]
3784+
if level is not None and self._is_multi:
3785+
# "Index" has no attribute "levels"; maybe "nlevels"?
3786+
idx = self.levels[level] # type: ignore[attr-defined]
3787+
else:
3788+
idx = self
3789+
target = idx[:0]
37853790
else:
37863791
target = ensure_index(target)
37873792

37883793
if level is not None:
37893794
if method is not None:
37903795
raise TypeError("Fill method not supported if level passed")
3791-
_, indexer, _ = self._join_level(target, level, how="right")
3796+
3797+
# TODO: tests where passing `keep_order=not self._is_multi`
3798+
# makes a difference for non-MultiIndex case
3799+
target, indexer, _ = self._join_level(
3800+
target, level, how="right", keep_order=not self._is_multi
3801+
)
3802+
37923803
else:
37933804
if self.equals(target):
37943805
indexer = None
@@ -3797,6 +3808,8 @@ def reindex(
37973808
indexer = self.get_indexer(
37983809
target, method=method, limit=limit, tolerance=tolerance
37993810
)
3811+
elif self._is_multi:
3812+
raise ValueError("cannot handle a non-unique multi-index!")
38003813
else:
38013814
if method is not None or limit is not None:
38023815
raise ValueError(
@@ -3805,11 +3818,18 @@ def reindex(
38053818
)
38063819
indexer, _ = self.get_indexer_non_unique(target)
38073820

3821+
target = self._wrap_reindex_result(target, indexer, preserve_names)
3822+
return target, indexer
3823+
3824+
def _wrap_reindex_result(self, target, indexer, preserve_names: bool):
3825+
target = self._maybe_preserve_names(target, preserve_names)
3826+
return target
3827+
3828+
def _maybe_preserve_names(self, target: Index, preserve_names: bool):
38083829
if preserve_names and target.nlevels == 1 and target.name != self.name:
3809-
target = target.copy()
3830+
target = target.copy(deep=False)
38103831
target.name = self.name
3811-
3812-
return target, indexer
3832+
return target
38133833

38143834
@final
38153835
def _reindex_non_unique(

pandas/core/indexes/multi.py

+8-48
Original file line numberDiff line numberDiff line change
@@ -2476,51 +2476,7 @@ def sortlevel(
24762476

24772477
return new_index, indexer
24782478

2479-
def reindex(
2480-
self, target, method=None, level=None, limit=None, tolerance=None
2481-
) -> tuple[MultiIndex, np.ndarray | None]:
2482-
"""
2483-
Create index with target's values (move/add/delete values as necessary)
2484-
2485-
Returns
2486-
-------
2487-
new_index : pd.MultiIndex
2488-
Resulting index
2489-
indexer : np.ndarray[np.intp] or None
2490-
Indices of output values in original index.
2491-
2492-
"""
2493-
# GH6552: preserve names when reindexing to non-named target
2494-
# (i.e. neither Index nor Series).
2495-
preserve_names = not hasattr(target, "names")
2496-
2497-
if level is not None:
2498-
if method is not None:
2499-
raise TypeError("Fill method not supported if level passed")
2500-
2501-
# GH7774: preserve dtype/tz if target is empty and not an Index.
2502-
# target may be an iterator
2503-
target = ibase.ensure_has_len(target)
2504-
if len(target) == 0 and not isinstance(target, Index):
2505-
idx = self.levels[level]
2506-
target = idx[:0]
2507-
else:
2508-
target = ensure_index(target)
2509-
target, indexer, _ = self._join_level(
2510-
target, level, how="right", keep_order=False
2511-
)
2512-
else:
2513-
target = ensure_index(target)
2514-
if self.equals(target):
2515-
indexer = None
2516-
else:
2517-
if self.is_unique:
2518-
indexer = self.get_indexer(
2519-
target, method=method, limit=limit, tolerance=tolerance
2520-
)
2521-
else:
2522-
raise ValueError("cannot handle a non-unique multi-index!")
2523-
2479+
def _wrap_reindex_result(self, target, indexer, preserve_names: bool):
25242480
if not isinstance(target, MultiIndex):
25252481
if indexer is None:
25262482
target = self
@@ -2531,16 +2487,20 @@ def reindex(
25312487
target = MultiIndex.from_tuples(target)
25322488
except TypeError:
25332489
# not all tuples, see test_constructor_dict_multiindex_reindex_flat
2534-
return target, indexer
2490+
return target
2491+
2492+
target = self._maybe_preserve_names(target, preserve_names)
2493+
return target
2494+
2495+
def _maybe_preserve_names(self, target: Index, preserve_names: bool):
25352496
if (
25362497
preserve_names
25372498
and target.nlevels == self.nlevels
25382499
and target.names != self.names
25392500
):
25402501
target = target.copy(deep=False)
25412502
target.names = self.names
2542-
2543-
return target, indexer
2503+
return target
25442504

25452505
# --------------------------------------------------------------------
25462506
# Indexing Methods

0 commit comments

Comments
 (0)