Skip to content
This repository

ENH: make array_equal+array_equiv work for record arrays/structured arrays #146

Closed
wants to merge 2 commits into from

3 participants

Derek Homeier Mark Charles Harris
Derek Homeier

Implementation of http://projects.scipy.org/numpy/ticket/1941 with tests. Please comment if the behaviour of array_equiv in commit 4b896f8 or in HEAD is preferred.

added some commits
ENH: enable comparison of structured arrays with array_equal|equiv 4b896f8
Extended the definition of array_equiv to different field names
Modified array_equiv to consider structured arrays with differently
named fields, but equivalent data, to be equivalent.
c036bce
Mark
Collaborator

I'd much prefer for the names to match exactly, matching the way NumPy already does struct array comparison:

>>> x = np.array([(0,1),(2,3)], dtype=[('a', 'i4'), ('b', 'i4')])
>>> y = np.array([(0,1),(2,3)], dtype=[('a', 'i4'), ('b', 'i4')])
>>> x == y
array([ True,  True], dtype=bool)
>>> y = np.array([(0,1),(2,4)], dtype=[('a', 'i4'), ('b', 'i4')])
>>> x == y
array([ True, False], dtype=bool)
>>> y = np.array([(0,1),(2,3)], dtype=[('a', 'i4'), ('c', 'i4')])
>>> x == y
False
Derek Homeier

That would make the difference between array_equal and array_equiv - but structure array comparison seems to behave similar to both, so maybe it's really a matter of taste:

>>> x = np.array([(0,1),(2,3)], dtype=[('a', 'i4'), ('b', 'i4')])
>>> y = np.array([(0,1),(2,3)], dtype=[('a', 'i4'), ('b', 'i4')]).reshape(1,-1)
>>> x == y
array([[ True,  True]], dtype=bool)

I was not aware that '==' did work already, so maybe most of the array_equal code could simply be replaced by

return bool((a1 == a2).all())

?

Mark
Collaborator

I actually fixed the == in 1.6. It had already been implemented, but incorrectly. I think even just

return (a1 == a2).all()

should be fine, but it's worth having tests which confirm this. One thing to think about for the future, is that I think == for struct dtypes should return a struct dtype with matching names but all 'bool' dtypes, and all() should be extended to reduce the bool-struct to a single value as well... The above line of code would still work correctly with these changes, so that's good.

Charles Harris
Owner
charris commented

@dhomeier How does this story end?

Charles Harris
Owner
charris commented

Closed by #3322.

Charles Harris charris closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Showing 2 unique commits by 1 author.

Aug 26, 2011
ENH: enable comparison of structured arrays with array_equal|equiv 4b896f8
Extended the definition of array_equiv to different field names
Modified array_equiv to consider structured arrays with differently
named fields, but equivalent data, to be equivalent.
c036bce
This page is out of date. Refresh to see the latest.
25  numpy/core/numeric.py
@@ -1924,7 +1924,8 @@ def allclose(a, b, rtol=1.e-5, atol=1.e-8):
1924 1924
 
1925 1925
 def array_equal(a1, a2):
1926 1926
     """
1927  
-    True if two arrays have the same shape and elements, False otherwise.
  1927
+    True if two arrays have the same shape and elements, including field
  1928
+    names (dtype.names) for structured arrays. False otherwise.
1928 1929
 
1929 1930
     Parameters
1930 1931
     ----------
@@ -1961,7 +1962,15 @@ def array_equal(a1, a2):
1961 1962
         return False
1962 1963
     if a1.shape != a2.shape:
1963 1964
         return False
1964  
-    return bool(logical_and.reduce(equal(a1,a2).ravel()))
  1965
+    # test for structured arrays
  1966
+    if a1.dtype.names:
  1967
+        if a1.dtype != a2.dtype:
  1968
+            return False
  1969
+        return bool( all([ logical_and.reduce(equal(a1[n],a2[n]).ravel())
  1970
+                           for n in a1.dtype.names ]) )
  1971
+    else:
  1972
+        return bool(logical_and.reduce(equal(a1,a2).ravel()))
  1973
+
1965 1974
 
1966 1975
 def array_equiv(a1, a2):
1967 1976
     """
@@ -1969,6 +1978,8 @@ def array_equiv(a1, a2):
1969 1978
 
1970 1979
     Shape consistent means they are either the same shape, or one input array
1971 1980
     can be broadcasted to create the same shape as the other one.
  1981
+    Fields of structured arrays are considered consistent if all fields are
  1982
+    consistent (in order of dtype), even if they are differently named.
1972 1983
 
1973 1984
     Parameters
1974 1985
     ----------
@@ -2002,8 +2013,16 @@ def array_equiv(a1, a2):
2002 2013
         a1, a2 = asarray(a1), asarray(a2)
2003 2014
     except:
2004 2015
         return False
  2016
+    # for structured arrays try to compare all fields,
  2017
+    # even if they have different names
2005 2018
     try:
2006  
-        return bool(logical_and.reduce(equal(a1,a2).ravel()))
  2019
+        if a1.dtype.names:
  2020
+            if len(a1.dtype.names) != len(a2.dtype.names):
  2021
+                return False
  2022
+            return bool( all([logical_and.reduce(equal(a1[n],a2[m]).ravel())
  2023
+                              for n,m in zip(a1.dtype.names,a2.dtype.names)]) )
  2024
+        else:
  2025
+            return bool(logical_and.reduce(equal(a1,a2).ravel()))
2007 2026
     except ValueError:
2008 2027
         return False
2009 2028
 
25  numpy/core/tests/test_numeric.py
@@ -640,7 +640,15 @@ def test_array_equal(self):
640 640
         res = array_equal(array([1,2]), array([1,3]))
641 641
         assert_(not res)
642 642
         assert_(type(res) is bool)
643  
-
  643
+        res = array_equal(array((1,2), dtype=[('i','i4'),('v','f8')]),
  644
+                          array((1,2), dtype=[('i','i4'),('v','f8')]))
  645
+        assert_(res)
  646
+        assert_(type(res) is bool)
  647
+        res = array_equal(array((1,2), dtype=[('i','i4'),('v','f8')]),
  648
+                          array((1,2), dtype=[('n','i4'),('f','f8')]))
  649
+        assert_(not res)
  650
+        assert_(type(res) is bool)
  651
+                
644 652
     def test_array_equiv(self):
645 653
         res = array_equiv(array([1,2]), array([1,2]))
646 654
         assert_(res)
@@ -670,7 +678,20 @@ def test_array_equiv(self):
670 678
         res = array_equiv(array([1,2]), array([[1,2,3],[4,5,6],[7,8,9]]))
671 679
         assert_(not res)
672 680
         assert_(type(res) is bool)
673  
-
  681
+        res = array_equiv(array((1,2), dtype=[('i','i4'),('v','f8')]),
  682
+                          array((1,2), dtype=[('i','i4'),('v','f8')]))
  683
+        assert_(res)
  684
+        assert_(type(res) is bool)
  685
+        res = array_equiv(array([(1,2),(3,4)],
  686
+                                dtype=[('i','i4'),('v','f8')]),
  687
+                          array([(1,2),(3,4)],
  688
+                                dtype=[('i','i4'),('v','f8')]).reshape((1,-1)))
  689
+        assert_(res)
  690
+        assert_(type(res) is bool)
  691
+        res = array_equiv(array((1,2), dtype=[('i','i4'),('v','f8')]),
  692
+                          array((1,2), dtype=[('n','i4'),('f','f8')]))
  693
+        assert_(res)
  694
+        assert_(type(res) is bool)
674 695
 
675 696
 def assert_array_strict_equal(x, y):
676 697
     assert_array_equal(x, y)
Commit_comment_tip

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.