Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

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

Closed
wants to merge 2 commits into from

3 participants

@dhomeier

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.

Derek Homeier added some commits
Derek Homeier ENH: enable comparison of structured arrays with array_equal|equiv 4b896f8
Derek Homeier 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
@mwiebe
Owner

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
@dhomeier

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())

?

@mwiebe
Owner

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.

@charris
Owner

@dhomeier How does this story end?

@charris
Owner

Closed by #3322.

@charris charris closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Aug 26, 2011
  1. Extended the definition of array_equiv to different field names

    Derek Homeier authored
    Modified array_equiv to consider structured arrays with differently
    named fields, but equivalent data, to be equivalent.
This page is out of date. Refresh to see the latest.
Showing with 45 additions and 5 deletions.
  1. +22 −3 numpy/core/numeric.py
  2. +23 −2 numpy/core/tests/test_numeric.py
View
25 numpy/core/numeric.py
@@ -1924,7 +1924,8 @@ def allclose(a, b, rtol=1.e-5, atol=1.e-8):
def array_equal(a1, a2):
"""
- True if two arrays have the same shape and elements, False otherwise.
+ True if two arrays have the same shape and elements, including field
+ names (dtype.names) for structured arrays. False otherwise.
Parameters
----------
@@ -1961,7 +1962,15 @@ def array_equal(a1, a2):
return False
if a1.shape != a2.shape:
return False
- return bool(logical_and.reduce(equal(a1,a2).ravel()))
+ # test for structured arrays
+ if a1.dtype.names:
+ if a1.dtype != a2.dtype:
+ return False
+ return bool( all([ logical_and.reduce(equal(a1[n],a2[n]).ravel())
+ for n in a1.dtype.names ]) )
+ else:
+ return bool(logical_and.reduce(equal(a1,a2).ravel()))
+
def array_equiv(a1, a2):
"""
@@ -1969,6 +1978,8 @@ def array_equiv(a1, a2):
Shape consistent means they are either the same shape, or one input array
can be broadcasted to create the same shape as the other one.
+ Fields of structured arrays are considered consistent if all fields are
+ consistent (in order of dtype), even if they are differently named.
Parameters
----------
@@ -2002,8 +2013,16 @@ def array_equiv(a1, a2):
a1, a2 = asarray(a1), asarray(a2)
except:
return False
+ # for structured arrays try to compare all fields,
+ # even if they have different names
try:
- return bool(logical_and.reduce(equal(a1,a2).ravel()))
+ if a1.dtype.names:
+ if len(a1.dtype.names) != len(a2.dtype.names):
+ return False
+ return bool( all([logical_and.reduce(equal(a1[n],a2[m]).ravel())
+ for n,m in zip(a1.dtype.names,a2.dtype.names)]) )
+ else:
+ return bool(logical_and.reduce(equal(a1,a2).ravel()))
except ValueError:
return False
View
25 numpy/core/tests/test_numeric.py
@@ -640,7 +640,15 @@ def test_array_equal(self):
res = array_equal(array([1,2]), array([1,3]))
assert_(not res)
assert_(type(res) is bool)
-
+ res = array_equal(array((1,2), dtype=[('i','i4'),('v','f8')]),
+ array((1,2), dtype=[('i','i4'),('v','f8')]))
+ assert_(res)
+ assert_(type(res) is bool)
+ res = array_equal(array((1,2), dtype=[('i','i4'),('v','f8')]),
+ array((1,2), dtype=[('n','i4'),('f','f8')]))
+ assert_(not res)
+ assert_(type(res) is bool)
+
def test_array_equiv(self):
res = array_equiv(array([1,2]), array([1,2]))
assert_(res)
@@ -670,7 +678,20 @@ def test_array_equiv(self):
res = array_equiv(array([1,2]), array([[1,2,3],[4,5,6],[7,8,9]]))
assert_(not res)
assert_(type(res) is bool)
-
+ res = array_equiv(array((1,2), dtype=[('i','i4'),('v','f8')]),
+ array((1,2), dtype=[('i','i4'),('v','f8')]))
+ assert_(res)
+ assert_(type(res) is bool)
+ res = array_equiv(array([(1,2),(3,4)],
+ dtype=[('i','i4'),('v','f8')]),
+ array([(1,2),(3,4)],
+ dtype=[('i','i4'),('v','f8')]).reshape((1,-1)))
+ assert_(res)
+ assert_(type(res) is bool)
+ res = array_equiv(array((1,2), dtype=[('i','i4'),('v','f8')]),
+ array((1,2), dtype=[('n','i4'),('f','f8')]))
+ assert_(res)
+ assert_(type(res) is bool)
def assert_array_strict_equal(x, y):
assert_array_equal(x, y)
Something went wrong with that request. Please try again.