6

我想在一个类上实现一个 equals 方法,其中实例的相等性源自包含列表的“弱”相等性,即列表元素的相同顺序不是必需的,而java.util.List.equals(Object)(您可以在下面查看它的 javadoc)要求相同的顺序。

那么,对列表执行与顺序无关的相等检查的最佳方法是什么?


我想将列表包装成新列表,对它们进行排序,然后在那里执行等于。

或另一种方法(这会使这个问题过时):改用 TreeSet,这样元素的顺序在具有相同元素的集合中总是相同的。

/**
 * 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);

我知道答案并关闭了标签。之后,我阅读了一篇关于 meta 的帖子,介绍了在这种情况下该怎么做。但由于我的问题被 SO 缓存了,我还是要发布它。也许将来有人会遇到同样的“问题”。如果没有人这样做,我将发布答案。

4

4 回答 4

6

如果您对添加 3rd 方库没有异议,您可以使用CollectionUtils.isEqualCollection(java.util.Collection a, java.util.Collection b)Apache Commons-Lang。它本质上比较两个任意集合(也是列表),忽略元素的顺序。

从 API 文档:

如果给定的 Collections 包含具有完全相同基数的完全相同的元素,则返回 true。也就是说,对于 a 或 b 中的每个元素 e,如果 a 中的 e 的基数等于 b 中的 e 的基数。

于 2013-08-28T16:24:21.843 回答
2

如果您使用的是Eclipse Collections,则可以将两个 List 都转换为 Bags 并在 Bags 之间使用 equals() 。的约定Bag.equals()是,如果两个 Bags 的每个元素的数量相同,则它们是相等的,但顺序不考虑在内。还有性能优势。toBag()并且Bag.equals()都是 O(n),所以这种方法比排序列表更快。

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

注意:我是 Eclipse Collections 的提交者。

于 2013-08-28T21:37:19.240 回答
1

我可以想到几种方法来做到这一点,包括迭代列表和使用list.containsSotirios 在他的评论中提到的。另一种是使用(new HashSet(list1)).equals(new HashSet(list2))(但是这两种解决方案都会丢弃重复的条目)。

另一种包括测试重复条目等效性的方法是使用Collections.sort()对两个列表进行排序副本,然后.equals()以这种方式进行比较。有多种合理的方法可以做到这一点,可能比我在这里提到的要多得多。

于 2013-08-28T16:10:10.413 回答
1

因为已经有了一些答案。我要发布我的。

我终于用了java.util.List.containsAll(Collection<?>)。我绊倒这种方法是我不想发布问题的原因。

@jarnbjo 没有意识到您还可以考虑基数维度!

编辑

增加了某事。解决基数问题。

  Collection<Object> a, b;

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

但这也可能失败。如果集合 a 有两次项目 x,而集合 b 有两次项目 y。然后尺寸相同并且containsAll()产量相同true

于 2013-08-28T16:29:46.157 回答