diff --git a/pandas/core/internals/array_manager.py b/pandas/core/internals/array_manager.py index 0f677ff3180be..a8493e647f39a 100644 --- a/pandas/core/internals/array_manager.py +++ b/pandas/core/internals/array_manager.py @@ -20,7 +20,7 @@ ) from pandas.core.dtypes.dtypes import ExtensionDtype, PandasDtype from pandas.core.dtypes.generic import ABCDataFrame, ABCSeries -from pandas.core.dtypes.missing import isna +from pandas.core.dtypes.missing import array_equals, isna import pandas.core.algorithms as algos from pandas.core.arrays import ExtensionArray @@ -829,9 +829,16 @@ def _make_na_array(self, fill_value=None): values.fill(fill_value) return values - def equals(self, other: object) -> bool: - # TODO - raise NotImplementedError + def _equal_values(self, other) -> bool: + """ + Used in .equals defined in base class. Only check the column values + assuming shape and indexes have already been checked. + """ + for left, right in zip(self.arrays, other.arrays): + if not array_equals(left, right): + return False + else: + return True def unstack(self, unstacker, fill_value) -> ArrayManager: """ diff --git a/pandas/core/internals/base.py b/pandas/core/internals/base.py index 2295e3f2c41b2..585a2dccf3acf 100644 --- a/pandas/core/internals/base.py +++ b/pandas/core/internals/base.py @@ -70,3 +70,25 @@ def reindex_axis( consolidate=consolidate, only_slice=only_slice, ) + + def _equal_values(self: T, other: T) -> bool: + """ + To be implemented by the subclasses. Only check the column values + assuming shape and indexes have already been checked. + """ + raise AbstractMethodError(self) + + def equals(self, other: object) -> bool: + """ + Implementation for DataFrame.equals + """ + if not isinstance(other, DataManager): + return False + + self_axes, other_axes = self.axes, other.axes + if len(self_axes) != len(other_axes): + return False + if not all(ax1.equals(ax2) for ax1, ax2 in zip(self_axes, other_axes)): + return False + + return self._equal_values(other) diff --git a/pandas/core/internals/managers.py b/pandas/core/internals/managers.py index 0aa97b4d6c0ed..80f5bdfc57f8a 100644 --- a/pandas/core/internals/managers.py +++ b/pandas/core/internals/managers.py @@ -1395,16 +1395,11 @@ def take(self, indexer, axis: int = 1, verify: bool = True, convert: bool = True consolidate=False, ) - def equals(self, other: object) -> bool: - if not isinstance(other, BlockManager): - return False - - self_axes, other_axes = self.axes, other.axes - if len(self_axes) != len(other_axes): - return False - if not all(ax1.equals(ax2) for ax1, ax2 in zip(self_axes, other_axes)): - return False - + def _equal_values(self: T, other: T) -> bool: + """ + Used in .equals defined in base class. Only check the column values + assuming shape and indexes have already been checked. + """ if self.ndim == 1: # For SingleBlockManager (i.e.Series) if other.ndim != 1: diff --git a/pandas/tests/frame/methods/test_equals.py b/pandas/tests/frame/methods/test_equals.py index dc45c9eb97ae4..ac9a66b4c7a6f 100644 --- a/pandas/tests/frame/methods/test_equals.py +++ b/pandas/tests/frame/methods/test_equals.py @@ -1,13 +1,8 @@ import numpy as np -import pandas.util._test_decorators as td - from pandas import DataFrame, date_range import pandas._testing as tm -# TODO(ArrayManager) implement equals -pytestmark = td.skip_array_manager_not_yet_implemented - class TestEquals: def test_dataframe_not_equal(self): @@ -16,13 +11,14 @@ def test_dataframe_not_equal(self): df2 = DataFrame({"a": ["s", "d"], "b": [1, 2]}) assert df1.equals(df2) is False - def test_equals_different_blocks(self): + def test_equals_different_blocks(self, using_array_manager): # GH#9330 df0 = DataFrame({"A": ["x", "y"], "B": [1, 2], "C": ["w", "z"]}) df1 = df0.reset_index()[["A", "B", "C"]] - # this assert verifies that the above operations have - # induced a block rearrangement - assert df0._mgr.blocks[0].dtype != df1._mgr.blocks[0].dtype + if not using_array_manager: + # this assert verifies that the above operations have + # induced a block rearrangement + assert df0._mgr.blocks[0].dtype != df1._mgr.blocks[0].dtype # do the real tests tm.assert_frame_equal(df0, df1)