简体   繁体   中英

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, ie 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.

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.

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.

I can think of several ways to do this, including iterating over a list and using list.contains as Sotirios mentions in his comment. Another would be to use (new HashSet(list1)).equals(new HashSet(list2)) (Both of these solutions would discard duplicate entries however).

Another way that would include testing for the equivalence of duplicate entries would be to use Collections.sort() to make sorted copies of both lists and then .equals() to compare that way. There's a variety of sound ways to do this, probably many more than I've mentioned here.

Since there are already some answers. I'm going to post mine.

I finally used java.util.List.containsAll(Collection<?>) . Me stumbling over this method was the reason I didn't want to post the question.

@jarnbjo Did not realize that there is also the dimension of cardinality you can consider!

EDIT

Added sth. to fix the cardinality problem.

  Collection<Object> a, b;

  boolean equal = (a.size() == b.size()) && a.containsAll(b);

But this could fail, too. If collection a has item x twice, and collection b has item y twice. Then the size is the same and containsAll() yields true .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM