1import numpy as np
2import pytest
3
4import pandas as pd
5from pandas import Index, MultiIndex, Series
6import pandas._testing as tm
7
8
9def test_equals(idx):
10    assert idx.equals(idx)
11    assert idx.equals(idx.copy())
12    assert idx.equals(idx.astype(object))
13
14    assert not idx.equals(list(idx))
15    assert not idx.equals(np.array(idx))
16
17    same_values = Index(idx, dtype=object)
18    assert idx.equals(same_values)
19    assert same_values.equals(idx)
20
21    if idx.nlevels == 1:
22        # do not test MultiIndex
23        assert not idx.equals(Series(idx))
24
25
26def test_equals_op(idx):
27    # GH9947, GH10637
28    index_a = idx
29
30    n = len(index_a)
31    index_b = index_a[0:-1]
32    index_c = index_a[0:-1].append(index_a[-2:-1])
33    index_d = index_a[0:1]
34    with pytest.raises(ValueError, match="Lengths must match"):
35        index_a == index_b
36    expected1 = np.array([True] * n)
37    expected2 = np.array([True] * (n - 1) + [False])
38    tm.assert_numpy_array_equal(index_a == index_a, expected1)
39    tm.assert_numpy_array_equal(index_a == index_c, expected2)
40
41    # test comparisons with numpy arrays
42    array_a = np.array(index_a)
43    array_b = np.array(index_a[0:-1])
44    array_c = np.array(index_a[0:-1].append(index_a[-2:-1]))
45    array_d = np.array(index_a[0:1])
46    with pytest.raises(ValueError, match="Lengths must match"):
47        index_a == array_b
48    tm.assert_numpy_array_equal(index_a == array_a, expected1)
49    tm.assert_numpy_array_equal(index_a == array_c, expected2)
50
51    # test comparisons with Series
52    series_a = Series(array_a)
53    series_b = Series(array_b)
54    series_c = Series(array_c)
55    series_d = Series(array_d)
56    with pytest.raises(ValueError, match="Lengths must match"):
57        index_a == series_b
58
59    tm.assert_numpy_array_equal(index_a == series_a, expected1)
60    tm.assert_numpy_array_equal(index_a == series_c, expected2)
61
62    # cases where length is 1 for one of them
63    with pytest.raises(ValueError, match="Lengths must match"):
64        index_a == index_d
65    with pytest.raises(ValueError, match="Lengths must match"):
66        index_a == series_d
67    with pytest.raises(ValueError, match="Lengths must match"):
68        index_a == array_d
69    msg = "Can only compare identically-labeled Series objects"
70    with pytest.raises(ValueError, match=msg):
71        series_a == series_d
72    with pytest.raises(ValueError, match="Lengths must match"):
73        series_a == array_d
74
75    # comparing with a scalar should broadcast; note that we are excluding
76    # MultiIndex because in this case each item in the index is a tuple of
77    # length 2, and therefore is considered an array of length 2 in the
78    # comparison instead of a scalar
79    if not isinstance(index_a, MultiIndex):
80        expected3 = np.array([False] * (len(index_a) - 2) + [True, False])
81        # assuming the 2nd to last item is unique in the data
82        item = index_a[-2]
83        tm.assert_numpy_array_equal(index_a == item, expected3)
84        tm.assert_series_equal(series_a == item, Series(expected3))
85
86
87def test_compare_tuple():
88    # GH#21517
89    mi = MultiIndex.from_product([[1, 2]] * 2)
90
91    all_false = np.array([False, False, False, False])
92
93    result = mi == mi[0]
94    expected = np.array([True, False, False, False])
95    tm.assert_numpy_array_equal(result, expected)
96
97    result = mi != mi[0]
98    tm.assert_numpy_array_equal(result, ~expected)
99
100    result = mi < mi[0]
101    tm.assert_numpy_array_equal(result, all_false)
102
103    result = mi <= mi[0]
104    tm.assert_numpy_array_equal(result, expected)
105
106    result = mi > mi[0]
107    tm.assert_numpy_array_equal(result, ~expected)
108
109    result = mi >= mi[0]
110    tm.assert_numpy_array_equal(result, ~all_false)
111
112
113def test_compare_tuple_strs():
114    # GH#34180
115
116    mi = MultiIndex.from_tuples([("a", "b"), ("b", "c"), ("c", "a")])
117
118    result = mi == ("c", "a")
119    expected = np.array([False, False, True])
120    tm.assert_numpy_array_equal(result, expected)
121
122    result = mi == ("c",)
123    expected = np.array([False, False, False])
124    tm.assert_numpy_array_equal(result, expected)
125
126
127def test_equals_multi(idx):
128    assert idx.equals(idx)
129    assert not idx.equals(idx.values)
130    assert idx.equals(Index(idx.values))
131
132    assert idx.equal_levels(idx)
133    assert not idx.equals(idx[:-1])
134    assert not idx.equals(idx[-1])
135
136    # different number of levels
137    index = MultiIndex(
138        levels=[Index(list(range(4))), Index(list(range(4))), Index(list(range(4)))],
139        codes=[
140            np.array([0, 0, 1, 2, 2, 2, 3, 3]),
141            np.array([0, 1, 0, 0, 0, 1, 0, 1]),
142            np.array([1, 0, 1, 1, 0, 0, 1, 0]),
143        ],
144    )
145
146    index2 = MultiIndex(levels=index.levels[:-1], codes=index.codes[:-1])
147    assert not index.equals(index2)
148    assert not index.equal_levels(index2)
149
150    # levels are different
151    major_axis = Index(list(range(4)))
152    minor_axis = Index(list(range(2)))
153
154    major_codes = np.array([0, 0, 1, 2, 2, 3])
155    minor_codes = np.array([0, 1, 0, 0, 1, 0])
156
157    index = MultiIndex(
158        levels=[major_axis, minor_axis], codes=[major_codes, minor_codes]
159    )
160    assert not idx.equals(index)
161    assert not idx.equal_levels(index)
162
163    # some of the labels are different
164    major_axis = Index(["foo", "bar", "baz", "qux"])
165    minor_axis = Index(["one", "two"])
166
167    major_codes = np.array([0, 0, 2, 2, 3, 3])
168    minor_codes = np.array([0, 1, 0, 1, 0, 1])
169
170    index = MultiIndex(
171        levels=[major_axis, minor_axis], codes=[major_codes, minor_codes]
172    )
173    assert not idx.equals(index)
174
175
176def test_identical(idx):
177    mi = idx.copy()
178    mi2 = idx.copy()
179    assert mi.identical(mi2)
180
181    mi = mi.set_names(["new1", "new2"])
182    assert mi.equals(mi2)
183    assert not mi.identical(mi2)
184
185    mi2 = mi2.set_names(["new1", "new2"])
186    assert mi.identical(mi2)
187
188    mi3 = Index(mi.tolist(), names=mi.names)
189    msg = r"Unexpected keyword arguments {'names'}"
190    with pytest.raises(TypeError, match=msg):
191        Index(mi.tolist(), names=mi.names, tupleize_cols=False)
192    mi4 = Index(mi.tolist(), tupleize_cols=False)
193    assert mi.identical(mi3)
194    assert not mi.identical(mi4)
195    assert mi.equals(mi4)
196
197
198def test_equals_operator(idx):
199    # GH9785
200    assert (idx == idx).all()
201
202
203def test_equals_missing_values():
204    # make sure take is not using -1
205    i = MultiIndex.from_tuples([(0, pd.NaT), (0, pd.Timestamp("20130101"))])
206    result = i[0:1].equals(i[0])
207    assert not result
208    result = i[1:2].equals(i[1])
209    assert not result
210
211
212def test_is_():
213    mi = MultiIndex.from_tuples(zip(range(10), range(10)))
214    assert mi.is_(mi)
215    assert mi.is_(mi.view())
216    assert mi.is_(mi.view().view().view().view())
217    mi2 = mi.view()
218    # names are metadata, they don't change id
219    mi2.names = ["A", "B"]
220    assert mi2.is_(mi)
221    assert mi.is_(mi2)
222
223    assert not mi.is_(mi.set_names(["C", "D"]))
224    mi2 = mi.view()
225    mi2.set_names(["E", "F"], inplace=True)
226    assert mi.is_(mi2)
227    # levels are inherent properties, they change identity
228    mi3 = mi2.set_levels([list(range(10)), list(range(10))])
229    assert not mi3.is_(mi2)
230    # shouldn't change
231    assert mi2.is_(mi)
232    mi4 = mi3.view()
233
234    # GH 17464 - Remove duplicate MultiIndex levels
235    with tm.assert_produces_warning(FutureWarning):
236        mi4.set_levels([list(range(10)), list(range(10))], inplace=True)
237    assert not mi4.is_(mi3)
238    mi5 = mi.view()
239    with tm.assert_produces_warning(FutureWarning):
240        mi5.set_levels(mi5.levels, inplace=True)
241    assert not mi5.is_(mi)
242
243
244def test_is_all_dates(idx):
245    assert not idx._is_all_dates
246
247
248def test_is_numeric(idx):
249    # MultiIndex is never numeric
250    assert not idx.is_numeric()
251
252
253def test_multiindex_compare():
254    # GH 21149
255    # Ensure comparison operations for MultiIndex with nlevels == 1
256    # behave consistently with those for MultiIndex with nlevels > 1
257
258    midx = MultiIndex.from_product([[0, 1]])
259
260    # Equality self-test: MultiIndex object vs self
261    expected = Series([True, True])
262    result = Series(midx == midx)
263    tm.assert_series_equal(result, expected)
264
265    # Greater than comparison: MultiIndex object vs self
266    expected = Series([False, False])
267    result = Series(midx > midx)
268    tm.assert_series_equal(result, expected)
269