 |
Comparing objects that might be arrays
Posted by emcmanus on July 20, 2007 at 07:50 AM | Comments (8)
I was using this Java idiom today, not for the first time, and thought I'd blog it for people not aware of it. You probably know that if you compare two objects x and y using x.equals(y), the result will be false if they are distinct arrays, even if their contents are the same. There is an easy way to get the right result for arrays. It is
Arrays.deepEquals(new Object[] {x}, new Object[] {y}). This works if x and y are plain objects, or null, or primitive arrays, or reference arrays. The only case where you might like it to work but it doesn't is for collections containing arrays, for example Set<int[]>.
Of course the idiom is a bit clunky and it's worth considering whether a new method
Something.deepEquals(Object x, Object y) might not be a useful addition. But where might it go? Arrays?
Bookmark blog post: del.icio.us Digg DZone Furl Reddit
Comments
Comments are listed in date ascending order (oldest first) | Post Comment
-
It's too specialised. Does it work for 2D arrays? Does it return true for 0-length arrays? 0-length arrays of different types? Related types (such as Number and Double)?
Why is it called deepEquals if it doesn't traverse arbitrary objects (something that serialisation is used for occasionally)?
Posted by: ricky_clarkson on July 20, 2007 at 09:37 AM
-
How about Collections?
Would you need one for every collection type?
Collections.listDeepEquals(List z, List y);
Collections.mapDeepEquals(Map z, Map y);
Collections.setDeepEquals(Set z, Set y);
Posted by: aberrant on July 20, 2007 at 09:38 AM
-
@ricky_clarkson - It looks like it works for n-dimensional arrays. From looking at the code thought it looks like it would return true for 0-length arrays of different types. Also related types would return false if I'm reading this correctly.
Posted by: aberrant on July 20, 2007 at 09:48 AM
-
Ricky, all of those cases do the right thing with the idiom I gave. 2D arrays will compare true if they have the same structure and the same elements. 0-length arrays will compare true if they are of the same type. Number is an abstract class so you can't have an object of that type, but e.g. f.equals(d) returns false if f is a Float and d is a Double, which is at least arguably right, and deepEquals does no differently.
Concerning the name, you certainly couldn't expect deepEquals to traverse truly arbitrary objects (even serialization only works for objects that follow certain rules). Perhaps it should be called deepishEquals?
Posted by: emcmanus on July 20, 2007 at 09:50 AM
-
aberrant, I would expect a collections-aware deepEquals to work whenever its Object arguments are in fact List or Map or Set or whatever. So its signature would be deepEquals(Object,Object), but it would work if given two Set<int[]> or whatever.
However I don't think this can really be made to work in general. We would need to change the semantics of Set.equals etc so that they compare the members using deepEquals instead of plain equals, and that would be an incompatible change. Otherwise, we could make it work for arrays of sets and sets of arrays and so on, but we couldn't make it work for arbitrary objects that might happen to contain sets of arrays.
Posted by: emcmanus on July 20, 2007 at 09:58 AM
-
Well when we place items in a TreeMap they don't always have to implement comparable. We can provide a comparator. Why not an Equalator then? That way we don't have to mess with the current Set functionality.
Posted by: aberrant on July 20, 2007 at 02:18 PM
-
The idea of an "Equator" interface or something similar is not new. There's a whole sea of RFEs reachable from 4269596 that touch on this question. They make interesting reading, to get an idea of the complexity of the question.
Really, the fundamental reason that deepEquals can't be made to work right in all cases is that arrays don't override the equals(Object) method to implement array equality. Of course it's too late to change things so that they do, because there'd be a very considerable risk of breaking existing code. Besides, array equality is non-trivial in the presence of Object[] arrays that contain themselves, so building that functionality into the language itself might not be a good idea.
Posted by: emcmanus on July 23, 2007 at 01:20 AM
-
Humm.. well I implemented some code ignoring collections that contain themselves, since Arrays.deepEquels() ignores that.
http://aberrantcode.blogspot.com/2007/07/collections-deepequals.html
I'll read up on 4269569 for more inspiration.
Posted by: aberrant on July 23, 2007 at 05:14 AM
|