diff --git a/pandas/_libs/lib.pyi b/pandas/_libs/lib.pyi index 9bc02e90ebb9e..2439082bf7413 100644 --- a/pandas/_libs/lib.pyi +++ b/pandas/_libs/lib.pyi @@ -240,3 +240,6 @@ def get_reverse_indexer( ) -> npt.NDArray[np.intp]: ... def is_bool_list(obj: list) -> bool: ... def dtypes_all_equal(types: list[DtypeObj]) -> bool: ... +def array_equal_fast( + left: np.ndarray, right: np.ndarray # np.ndarray[np.int64, ndim=1] +) -> bool: ... diff --git a/pandas/_libs/lib.pyx b/pandas/_libs/lib.pyx index b56cf2a23a45f..89e02ac0fa86d 100644 --- a/pandas/_libs/lib.pyx +++ b/pandas/_libs/lib.pyx @@ -50,6 +50,7 @@ from numpy cimport ( complex128_t, flatiter, float64_t, + int32_t, int64_t, intp_t, ndarray, @@ -642,6 +643,34 @@ def array_equivalent_object(ndarray left, ndarray right) -> bool: return True +ctypedef fused int6432_t: + int64_t + int32_t + + +@cython.wraparound(False) +@cython.boundscheck(False) +def array_equal_fast( + ndarray[int6432_t, ndim=1] left, ndarray[int6432_t, ndim=1] right, +) -> bool: + """ + Perform an element by element comparison on 1-d integer arrays, meant for indexer + comparisons + """ + cdef: + Py_ssize_t i, n = left.size + + if left.size != right.size: + return False + + for i in range(n): + + if left[i] != right[i]: + return False + + return True + + ctypedef fused ndarr_object: ndarray[object, ndim=1] ndarray[object, ndim=2] diff --git a/pandas/tests/libs/test_lib.py b/pandas/tests/libs/test_lib.py index fd7c47d47112f..e352250dc748d 100644 --- a/pandas/tests/libs/test_lib.py +++ b/pandas/tests/libs/test_lib.py @@ -243,6 +243,27 @@ def test_get_reverse_indexer(self): expected = np.array([4, 2, 3, 6, 7], dtype=np.intp) tm.assert_numpy_array_equal(result, expected) + @pytest.mark.parametrize("dtype", ["int64", "int32"]) + def test_array_equal_fast(self, dtype): + # GH#50592 + left = np.arange(1, 100, dtype=dtype) + right = np.arange(1, 100, dtype=dtype) + assert lib.array_equal_fast(left, right) + + @pytest.mark.parametrize("dtype", ["int64", "int32"]) + def test_array_equal_fast_not_equal(self, dtype): + # GH#50592 + left = np.array([1, 2], dtype=dtype) + right = np.array([2, 2], dtype=dtype) + assert not lib.array_equal_fast(left, right) + + @pytest.mark.parametrize("dtype", ["int64", "int32"]) + def test_array_equal_fast_not_equal_shape(self, dtype): + # GH#50592 + left = np.array([1, 2, 3], dtype=dtype) + right = np.array([2, 2], dtype=dtype) + assert not lib.array_equal_fast(left, right) + def test_cache_readonly_preserve_docstrings(): # GH18197