1
1
from copy import copy as copy_func
2
2
from datetime import datetime
3
+ from itertools import zip_longest
3
4
import operator
4
5
from textwrap import dedent
5
6
from typing import (
11
12
List ,
12
13
Optional ,
13
14
Sequence ,
15
+ Tuple ,
14
16
TypeVar ,
15
17
Union ,
16
18
)
@@ -2525,7 +2527,7 @@ def _get_reconciled_name_object(self, other):
2525
2527
"""
2526
2528
name = get_op_result_name (self , other )
2527
2529
if self .name != name :
2528
- return self ._shallow_copy ( name = name )
2530
+ return self .rename ( name )
2529
2531
return self
2530
2532
2531
2533
def _union_incompatible_dtypes (self , other , sort ):
@@ -2633,7 +2635,9 @@ def union(self, other, sort=None):
2633
2635
if not self ._can_union_without_object_cast (other ):
2634
2636
return self ._union_incompatible_dtypes (other , sort = sort )
2635
2637
2636
- return self ._union (other , sort = sort )
2638
+ result = self ._union (other , sort = sort )
2639
+
2640
+ return self ._wrap_setop_result (other , result )
2637
2641
2638
2642
def _union (self , other , sort ):
2639
2643
"""
@@ -2655,10 +2659,10 @@ def _union(self, other, sort):
2655
2659
Index
2656
2660
"""
2657
2661
if not len (other ) or self .equals (other ):
2658
- return self . _get_reconciled_name_object ( other )
2662
+ return self
2659
2663
2660
2664
if not len (self ):
2661
- return other . _get_reconciled_name_object ( self )
2665
+ return other
2662
2666
2663
2667
# TODO(EA): setops-refactor, clean all this up
2664
2668
lvals = self ._values
@@ -2700,12 +2704,16 @@ def _union(self, other, sort):
2700
2704
stacklevel = 3 ,
2701
2705
)
2702
2706
2703
- # for subclasses
2704
- return self ._wrap_setop_result (other , result )
2707
+ return self ._shallow_copy (result )
2705
2708
2706
2709
def _wrap_setop_result (self , other , result ):
2707
2710
name = get_op_result_name (self , other )
2708
- return self ._shallow_copy (result , name = name )
2711
+ if isinstance (result , Index ):
2712
+ if result .name != name :
2713
+ return result .rename (name )
2714
+ return result
2715
+ else :
2716
+ return self ._shallow_copy (result , name = name )
2709
2717
2710
2718
# TODO: standardize return type of non-union setops type(self vs other)
2711
2719
def intersection (self , other , sort = False ):
@@ -2775,15 +2783,12 @@ def intersection(self, other, sort=False):
2775
2783
indexer = algos .unique1d (Index (rvals ).get_indexer_non_unique (lvals )[0 ])
2776
2784
indexer = indexer [indexer != - 1 ]
2777
2785
2778
- taken = other .take (indexer )
2779
- res_name = get_op_result_name (self , other )
2786
+ result = other .take (indexer )
2780
2787
2781
2788
if sort is None :
2782
- taken = algos .safe_sort (taken .values )
2783
- return self ._shallow_copy (taken , name = res_name )
2789
+ result = algos .safe_sort (result .values )
2784
2790
2785
- taken .name = res_name
2786
- return taken
2791
+ return self ._wrap_setop_result (other , result )
2787
2792
2788
2793
def difference (self , other , sort = None ):
2789
2794
"""
@@ -5968,3 +5973,22 @@ def _maybe_asobject(dtype, klass, data, copy: bool, name: Label, **kwargs):
5968
5973
return index .astype (object )
5969
5974
5970
5975
return klass (data , dtype = dtype , copy = copy , name = name , ** kwargs )
5976
+
5977
+
5978
+ def get_unanimous_names (* indexes : Index ) -> Tuple [Label , ...]:
5979
+ """
5980
+ Return common name if all indices agree, otherwise None (level-by-level).
5981
+
5982
+ Parameters
5983
+ ----------
5984
+ indexes : list of Index objects
5985
+
5986
+ Returns
5987
+ -------
5988
+ list
5989
+ A list representing the unanimous 'names' found.
5990
+ """
5991
+ name_tups = [tuple (i .names ) for i in indexes ]
5992
+ name_sets = [{* ns } for ns in zip_longest (* name_tups )]
5993
+ names = tuple (ns .pop () if len (ns ) == 1 else None for ns in name_sets )
5994
+ return names
0 commit comments