diff --git a/doc/source/whatsnew/v0.24.2.rst b/doc/source/whatsnew/v0.24.2.rst index 6a9a316da1ec6..78c551906918e 100644 --- a/doc/source/whatsnew/v0.24.2.rst +++ b/doc/source/whatsnew/v0.24.2.rst @@ -45,7 +45,7 @@ Bug Fixes **Indexing** -- +- :meth:`Index.to_flat_index` now always returns an :class:`Index` containing tuples, even in the case the original object was already a flat :class:`Index` (:issue:`23670`). - - diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py index cf813f4c3030b..f662807d83094 100644 --- a/pandas/core/indexes/base.py +++ b/pandas/core/indexes/base.py @@ -1105,23 +1105,31 @@ def summary(self, name=None): def to_flat_index(self): """ - Identity method. + Convert a MultiIndex to an Index of Tuples containing the level values. .. versionadded:: 0.24.0 - This is implemented for compatability with subclass implementations - when chaining. - Returns ------- pd.Index - Caller. + Index with the MultiIndex data represented in Tuples. - See Also + Examples -------- - MultiIndex.to_flat_index : Subclass implementation. + >>> index = pd.MultiIndex.from_product( + ... [['foo', 'bar'], ['baz', 'qux']], + ... names=['a', 'b']) + >>> index.to_flat_index() + Index([('foo', 'baz'), ('foo', 'qux'), + ('bar', 'baz'), ('bar', 'qux')], + dtype='object') """ - return self + + from .multi import MultiIndex + if not isinstance(self, MultiIndex): + self = MultiIndex.from_product([self]) + + return Index(self.values, tupleize_cols=False) def to_series(self, index=None, name=None): """ diff --git a/pandas/core/indexes/multi.py b/pandas/core/indexes/multi.py index e2237afbcac0f..440ca6c4ae665 100644 --- a/pandas/core/indexes/multi.py +++ b/pandas/core/indexes/multi.py @@ -164,7 +164,6 @@ class MultiIndex(Index): set_levels set_codes to_frame - to_flat_index is_lexsorted sortlevel droplevel @@ -1523,34 +1522,6 @@ def to_hierarchical(self, n_repeat, n_shuffle=1): FutureWarning, stacklevel=2) return MultiIndex(levels=levels, codes=codes, names=names) - def to_flat_index(self): - """ - Convert a MultiIndex to an Index of Tuples containing the level values. - - .. versionadded:: 0.24.0 - - Returns - ------- - pd.Index - Index with the MultiIndex data represented in Tuples. - - Notes - ----- - This method will simply return the caller if called by anything other - than a MultiIndex. - - Examples - -------- - >>> index = pd.MultiIndex.from_product( - ... [['foo', 'bar'], ['baz', 'qux']], - ... names=['a', 'b']) - >>> index.to_flat_index() - Index([('foo', 'baz'), ('foo', 'qux'), - ('bar', 'baz'), ('bar', 'qux')], - dtype='object') - """ - return Index(self.values, tupleize_cols=False) - @property def is_all_dates(self): return False diff --git a/pandas/tests/indexes/multi/test_conversion.py b/pandas/tests/indexes/multi/test_conversion.py index 00b935521bac4..ef005043af7b7 100644 --- a/pandas/tests/indexes/multi/test_conversion.py +++ b/pandas/tests/indexes/multi/test_conversion.py @@ -214,11 +214,3 @@ def test_to_series_with_arguments(idx): assert s.values is not idx.values assert s.index is not idx assert s.name != idx.name - - -def test_to_flat_index(idx): - expected = pd.Index((('foo', 'one'), ('foo', 'two'), ('bar', 'one'), - ('baz', 'two'), ('qux', 'one'), ('qux', 'two')), - tupleize_cols=False) - result = idx.to_flat_index() - tm.assert_index_equal(result, expected) diff --git a/pandas/tests/indexes/test_common.py b/pandas/tests/indexes/test_common.py index fd356202a8ce5..1ef76c91e1337 100644 --- a/pandas/tests/indexes/test_common.py +++ b/pandas/tests/indexes/test_common.py @@ -113,12 +113,17 @@ def test_corner_union(self, indices, fname, sname, expected_name): tm.assert_index_equal(union, expected) def test_to_flat_index(self, indices): - # 22866 - if isinstance(indices, MultiIndex): - pytest.skip("Separate expectation for MultiIndex") + # 22866, 23670 result = indices.to_flat_index() - tm.assert_index_equal(result, indices) + + if isinstance(indices, MultiIndex): + values = [tuple(v) for v in indices] + else: + values = [(v,) for v in indices] + expected = pd.Index(values, tupleize_cols=False) + + tm.assert_index_equal(result, expected) def test_wrong_number_names(self, indices): with pytest.raises(ValueError, match="^Length"):