From 545ccc9d04221bc6be3fdda5b42fc6ddbcd03d5b Mon Sep 17 00:00:00 2001 From: phofl Date: Sat, 12 Dec 2020 13:00:51 +0100 Subject: [PATCH 1/3] CLN: MultiIndex.union to look like Index.union() --- pandas/core/indexes/multi.py | 15 ++++++++------- pandas/tests/indexes/multi/test_setops.py | 9 +++++++++ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/pandas/core/indexes/multi.py b/pandas/core/indexes/multi.py index 385b7e487d4c5..1edd98e980a2d 100644 --- a/pandas/core/indexes/multi.py +++ b/pandas/core/indexes/multi.py @@ -3566,18 +3566,19 @@ def union(self, other, sort=None): """ self._validate_sort_keyword(sort) self._assert_can_do_setop(other) - other, result_names = self._convert_can_do_setop(other) + other, _ = self._convert_can_do_setop(other) - if len(other) == 0 or self.equals(other): - return self.rename(result_names) + if not len(other) or self.equals(other): + return self._get_reconciled_name_object(other) + + if not len(self): + return other._get_reconciled_name_object(self) return self._union(other, sort=sort) def _union(self, other, sort): other, result_names = self._convert_can_do_setop(other) - # TODO: Index.union returns other when `len(self)` is 0. - if not is_object_dtype(other.dtype): raise NotImplementedError( "Can only union MultiIndex with MultiIndex or Index of tuples, " @@ -3608,10 +3609,10 @@ def _maybe_match_names(self, other): """ Try to find common names to attach to the result of an operation between a and b. Return a consensus list of names if they match at least partly - or None if they have completely different names. + or list of None if they have completely different names. """ if len(self.names) != len(other.names): - return None + return [None] * len(self.names) names = [] for a_name, b_name in zip(self.names, other.names): if a_name == b_name: diff --git a/pandas/tests/indexes/multi/test_setops.py b/pandas/tests/indexes/multi/test_setops.py index f9fc425e46696..e6a069926e2dd 100644 --- a/pandas/tests/indexes/multi/test_setops.py +++ b/pandas/tests/indexes/multi/test_setops.py @@ -460,3 +460,12 @@ def test_intersection_different_names(): mi2 = MultiIndex.from_arrays([[1], [3]]) result = mi.intersection(mi2) tm.assert_index_equal(result, mi2) + + +def test_union_empty_self_different_names(): + # GH# + mi = MultiIndex.from_arrays([[]]) + mi2 = MultiIndex.from_arrays([[1, 2], [3, 4]], names=["a", "b"]) + result = mi.union(mi2) + expected = MultiIndex.from_arrays([[1, 2], [3, 4]]) + tm.assert_index_equal(result, expected) From ec674e715bf587c4da31a2cc67cf84f3845f827f Mon Sep 17 00:00:00 2001 From: phofl Date: Sat, 12 Dec 2020 13:06:32 +0100 Subject: [PATCH 2/3] Fix failing tests --- pandas/tests/indexes/multi/test_setops.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pandas/tests/indexes/multi/test_setops.py b/pandas/tests/indexes/multi/test_setops.py index e6a069926e2dd..bdde03bd3701a 100644 --- a/pandas/tests/indexes/multi/test_setops.py +++ b/pandas/tests/indexes/multi/test_setops.py @@ -424,12 +424,12 @@ def test_intersect_with_duplicates(tuples, exp_tuples): @pytest.mark.parametrize( "data, names, expected", [ - ((1,), None, None), - ((1,), ["a"], None), - ((1,), ["b"], None), + ((1,), None, [None, None]), + ((1,), ["a"], [None, None]), + ((1,), ["b"], [None, None]), ((1, 2), ["c", "d"], [None, None]), ((1, 2), ["b", "a"], [None, None]), - ((1, 2, 3), ["a", "b", "c"], None), + ((1, 2, 3), ["a", "b", "c"], [None, None]), ((1, 2), ["a", "c"], ["a", None]), ((1, 2), ["c", "b"], [None, "b"]), ((1, 2), ["a", "b"], ["a", "b"]), From b977a9313b18dcbaa838f86ff5d59a19fb443c50 Mon Sep 17 00:00:00 2001 From: phofl Date: Sat, 12 Dec 2020 19:29:28 +0100 Subject: [PATCH 3/3] Move test --- pandas/tests/indexes/multi/test_setops.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/pandas/tests/indexes/multi/test_setops.py b/pandas/tests/indexes/multi/test_setops.py index bdde03bd3701a..a26eb793afe7e 100644 --- a/pandas/tests/indexes/multi/test_setops.py +++ b/pandas/tests/indexes/multi/test_setops.py @@ -387,6 +387,15 @@ def test_union_non_object_dtype_raises(): mi.union(idx) +def test_union_empty_self_different_names(): + # GH#38423 + mi = MultiIndex.from_arrays([[]]) + mi2 = MultiIndex.from_arrays([[1, 2], [3, 4]], names=["a", "b"]) + result = mi.union(mi2) + expected = MultiIndex.from_arrays([[1, 2], [3, 4]]) + tm.assert_index_equal(result, expected) + + @pytest.mark.parametrize( "method", ["union", "intersection", "difference", "symmetric_difference"] ) @@ -460,12 +469,3 @@ def test_intersection_different_names(): mi2 = MultiIndex.from_arrays([[1], [3]]) result = mi.intersection(mi2) tm.assert_index_equal(result, mi2) - - -def test_union_empty_self_different_names(): - # GH# - mi = MultiIndex.from_arrays([[]]) - mi2 = MultiIndex.from_arrays([[1, 2], [3, 4]], names=["a", "b"]) - result = mi.union(mi2) - expected = MultiIndex.from_arrays([[1, 2], [3, 4]]) - tm.assert_index_equal(result, expected)