在标准Java库中,查找两个列表是否包含完全相同的元素的最简单方法是什么?
如果两个列表是相同的实例,则无关紧要,列表的类型参数是否不同也无关紧要 .
例如
List list1
List<String> list2;
// ... construct etc
list1.add("A");
list2.add("A");
// the function, given these two lists, should return true
我知道可能有些东西盯着我:-)
编辑:为了澄清,我正在按顺序寻找完全相同的元素和元素数量 .
编辑:谢谢你指出我看不见的明显答案:-)
虽然到目前为止给出的所有答案都是正确的,但有些答案比其他答案更正确,所以在接受之前我会等待一段时间以获得最佳舍入答案 .
16 回答
汤姆的回答非常好我完全同意他的答案!
这个问题的一个有趣的方面是,你是否需要
List
类型本身及其固有的顺序 .如果不是,您可以降级为
Iterable
或Collection
这使您可以灵活地传递按插入时间排序的数据结构,而不是在您要检查时 .如果订单永远不重要(并且您没有重复的元素),请考虑使用
Set
.如果顺序很重要但是由插入时间定义(并且您没有重复项),请考虑
LinkedHashSet
,它类似于TreeSet但按插入时间排序(不计算重复项) . 这也为您提供了O(1)
的O(1)
摊销访问权限 .如果您关心订单,那么只需使用equals方法:
来自javadoc:
如果要独立于顺序进行检查,可以将所有元素复制到集合,并在结果集合上使用等于:
这种方法的局限在于它不仅忽略了顺序,而且忽略了重复元素的频率 . 例如,如果
list1
是["A","B","A"]且list2
是["A","B","B"],Set
方法会认为它们是相等的 .如果您需要对订单不敏感但对重复频率敏感,您可以:
在比较它们之前对两个列表(或副本)进行排序,如this answer to another question中所述
或将所有元素复制到Multiset
我在评论中发布了一些内容,我认为它保证了自己的答案 .
正如大家在这里所说,使用equals()取决于顺序 . 如果您不关心订单,您有3个选择 .
Option 1
使用
containsAll()
. 在我看来,这个选项并不理想,因为它提供了最差的性能,O(n ^ 2) .Option 2
这有两个变化:
2a) 如果您不关心维护列表的顺序...请在两个列表中使用
Collections.sort()
. 然后使用equals()
. 这是O(nlogn),因为你做了两种排序,然后是O(n)比较 .2b) 如果需要维护列表的顺序,可以先复制两个列表 . 然后,您可以在复制的列表上使用解决方案 2a . 然而,如果复制非常昂贵,这可能没有吸引力 .
这导致:
Option 3
如果您的要求与零件 2b 相同,但复制过于昂贵 . 您可以使用TreeSet为您进行排序 . 将每个列表转储到自己的TreeSet中 . 它将在集合中排序,原始列表将保持不变 . 然后在
TreeSet
上执行equals()
比较 .TreeSets
可以在O(nlogn)时间内构建,equals()
可以是O(n) .拿你的选择:-) .
EDIT: 我几乎忘记了Laurence Gonsalves指出的同一个警告 . TreeSet实现将消除重复 . 如果您关心重复项,则需要某种排序的多重集 .
如果你正在使用(或者很乐意使用)Apache Commons Collections,你可以使用CollectionUtils.isEqualCollection,其中"returns true iff the given Collections contain exactly the same elements with exactly the same cardinalities."
我知道这是一个旧线程,但其他答案都没有完全解决我的用例(我猜Guava Multiset可能也会这样做,但这里没有例子) . 请原谅我的格式 . 我仍然很想在堆栈交换上发帖 . 另外,如果有任何错误,请告诉我
假设您有
List<T>
a和List<T>
b并且您想要检查它们是否与以下条件相同:1)O(n)预期运行时间
2)等式定义为:对于a或b中的所有元素,元素在a中出现的次数等于元素在b中出现的次数 . 元素相等定义为T.equals()
运行时间是O(n)因为我们正在对散列映射进行O(2 * n)插入,并且O(3 * n)散列映射选择 . 我还没有完全测试这段代码,所以要小心:)
聚会很晚但想要添加这个空的安全检查:
试试这个版本不要求顺序相同,但支持多个相同的值 . 它们只有在每个具有相同数量的任何值时才匹配 .
解决两个列表具有相同元素但顺序不同的情况:
List上的equals方法将执行此操作,列表是有序的,因此要等于两个列表必须具有相同顺序的相同元素 .
示例代码:
除了劳伦斯的答案,如果你还想让它安全无效:
如果列表包含自定义类MyClass,则此类必须覆盖
equals
函数 .注意:如果要在java.util.Set而不是
java.util.List
上测试equals,那么您的对象必须覆盖hashCode
函数 .List.equals()
http://java.sun.com/j2se/1.5/docs/api/java/util/List.html#equals(java.lang.Object)
您可以使用Apache的org.apache.commons.collections库:http://commons.apache.org/collections/apidocs/org/apache/commons/collections/ListUtils.html
检查两个列表都不为空 . 如果它们的大小不同,那么这些列表就不相同了 . 构建包含列表元素作为键及其重复值的映射,并比较映射 .
假设,如果两个列表都为空,我认为它们是相等的 .
请注意,应该为这些对象正确定义方法等于 . https://stackoverflow.com/a/24814634/4587961
这取决于您使用的具体List类 . 抽象类AbstractCollection有一个名为containsAll(Collection)的方法,它接受另一个集合(List是一个集合)和:
因此,如果传入ArrayList,您可以调用此方法以查看它们是否完全相同 .
containsAll()的原因是因为它遍历第一个列表,在第二个列表中查找匹配项 . 因此,如果它们发生故障,则equals()将不会接收它 .
编辑:我只想在这里评论一下执行所提供的各种选项的摊销运行时间 . 运行时间重要吗?当然 . 这是你唯一应该考虑的事情吗?没有 .
将每个单个元素从列表复制到其他列表的成本需要花费时间,并且它还占用了大量内存(有效地使您使用的内存加倍) .
因此,如果JVM中的内存不是问题(通常应该是这样),那么您仍然需要考虑将两个列表中的每个元素复制到两个TreeSet中所花费的时间 . 请记住,它会在每个元素进入时对其进行排序 .
我最后的建议?在此处做出正确决策之前,您需要考虑数据集以及数据集中的元素数量,以及数据集中每个对象的大小 . 与他们一起玩,每个方向创建一个,看看哪一个运行得更快 . 这是一个很好的锻炼 .