Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I perform an order-independent equality check on lists?

I want to implement an equals method on a class where the equality of instances is derived from the 'weak' equality of the contained lists, i. e. the same order of the list elements is not necessary, whereas java.util.List.equals(Object) (you can see its javadoc below) demands the same order.

So, what's the best way to perform an order-independent equality check on lists?


I thought of wrapping the lists into new lists, sorting them and then performing the equals there on.

Or another approach (that would make this question obsolete): Use a TreeSet instead, this way the order of the elements would always be the same in sets with equal elements.

/**
 * Compares the specified object with this list for equality.  Returns
 * <tt>true</tt> if and only if the specified object is also a list, both
 * lists have the same size, and all corresponding pairs of elements in
 * the two lists are <i>equal</i>.  (Two elements <tt>e1</tt> and
 * <tt>e2</tt> are <i>equal</i> if <tt>(e1==null ? e2==null :
 * e1.equals(e2))</tt>.)  In other words, two lists are defined to be
 * equal if they contain the same elements in the same order.  This
 * definition ensures that the equals method works properly across
 * different implementations of the <tt>List</tt> interface.
 *
 * @param o the object to be compared for equality with this list
 * @return <tt>true</tt> if the specified object is equal to this list
 */
boolean equals(Object o);

I know the answer and closed the tab. Afterwards I read a post on meta about what to do in these kind of situations. But since my question was cached by SO, I'm going to post it anyway. Maybe someone has the same 'problem' in future. I'm going to post the answer, if no one does.

like image 829
mike Avatar asked Aug 28 '13 15:08

mike


2 Answers

If you have no objections against adding 3rd party libraries, you can use CollectionUtils.isEqualCollection(java.util.Collection a, java.util.Collection b) from Apache Commons-Lang. It essentially compares two arbitrary collection (also Lists), ignoring the order of the elements.

From the API documentation:

Returns true iff the given Collections contain exactly the same elements with exactly the same cardinalities. That is, iff the cardinality of e in a is equal to the cardinality of e in b, for each element e in a or b.

like image 175
jarnbjo Avatar answered Oct 13 '22 00:10

jarnbjo


If you're using Eclipse Collections, you can convert both Lists to Bags and just use equals() between the Bags. The contract of Bag.equals() is that two Bags are equal if they have the same number of each element, but order doesn't factor in. There's a performance benefit too. toBag() and Bag.equals() are each O(n), so this method is faster than sorting the Lists.

Assert.assertEquals(
    Lists.mutable.with(1, 2, 3, 1).toBag(),
    Lists.mutable.with(3, 2, 1, 1).toBag());

Note: I am a committer for Eclipse Collections.

like image 23
Craig P. Motlin Avatar answered Oct 13 '22 01:10

Craig P. Motlin