简单的方法来查找两个不同的列表是否包含完全相同的元素?

在标准Java库中查找两个列表是否包含完全相同的元素的最简单方法是什么?

这两个列表是否是相同的实例并不重要,如果列表的types参数不同,应该没有关系。

例如

List list1 List<String> list2; // ... construct etc list1.add("A"); list2.add("A"); // the function, given these two lists, should return true 

有可能是我在脸上盯着我:-)


编辑:澄清,我正在寻找相同的元素和数量的元素,依次。


编辑:感谢指出明显的答案,我看不到看:-)

尽pipe到目前为止所给出的答案都是正确的,但有些答案是比其他答案更为正确的,所以在接受之前,我会等待一段最佳的四舍五入答案。

如果你关心订单,那么只需使用equals方法:

 list1.equals(list2) 

从javadoc:

将指定的对象与此列表进行比较以获得相等性。 当且仅当指定的对象也是一个列表时,才返回true,两个列表具有相同的大小,并且两个列表中所有相应的元素对相等。 (如果(e1 == null?e2 == null:e1.equals(e2)),两个元素e1和e2是相等的。)换句话说,如果两个列表包含相同元素的顺序相同。 此定义确保了equals方法在List接口的不同实现之间正常工作。

如果要独立检查顺序,则可以将所有元素复制到集合中,并在生成的集合上使用equals:

 public static <T> boolean listEqualsIgnoreOrder(List<T> list1, List<T> list2) { return new HashSet<>(list1).equals(new HashSet<>(list2)); } 

这种方法的一个警告是,它不会完全检查重复。 例如:如果list1是[“A”,“B”,“A”],list2是[“A”,“B”,“B”],Set方法会说他们是相等的。

如果你不希望这些被视为平等的,但你不关心秩序,你可以在比较它们之前对这两个列表进行sorting,或者你可以做同样的事情作为设置的方法,但与Multiset (不是标准的一部分图书馆,但谷歌番石榴有一个很好的)。

我发表了一些评论,我认为这是自己的答案。

正如大家所说,使用equals()取决于顺序。 如果你不关心订单,你有3个选项。

选项1

使用containsAll() 。 在我看来,这个选项并不理想,因为它提供了最差的performance,O(n ^ 2)。

选项2

有两个变化:

2a)如果你不关心维护你的列表的顺序…在列表上使用Collections.sort() 。 然后使用equals() 。 这是O(nlogn),因为你做了两种,然后是一个O(n)的比较。

2b)如果您需要维护列表的顺序,您可以先复制这两个列表。 那么您可以在复制列表上使用解决scheme2a 。 然而,如果复制非常昂贵,这可能是没有吸引力的。

这导致:

选项3

如果您的要求与第2b部分相同,但是复制太昂贵。 您可以使用TreeSet为您进行sorting。 将每个列表转储到它自己的TreeSet中。 它将被sorting在集合中,原始列表将保持不变。 然后在两个TreeSet上执行equals()比较。 TreeSets可以在O(nlogn)时间内build立, equals()是O(n)。

把你的select:-)。

编辑:我几乎忘记了劳伦斯贡萨尔维斯指出的同样的警告。 TreeSet实现将消除重复。 如果你在意重复,你将需要某种sorting的多重集。

我知道这是一个古老的线程,但我张贴这个答案,因为这是谷歌的第一次打,没有其他答案完全解决了我的用例(我猜Guava Multiset可能也是这样做的,但是这里没有例子) 。 请原谅我的格式。 我还是新来张贴交换。 另外让我知道是否有任何错误

比方说你有List<T> a和List<T> b,你想检查它们是否与下列条件相等:

1)O(n)预计运行时间
2)相等定义为:对于a或b中的所有元素,元素在a中出现的次数等于元素出现在b中的次数。 元素相等被定义为T.equals()

 private boolean listsAreEquivelent(List<? extends Object> a, List<? extends Object> b) { if(a==null) { if(b==null) { //Here 2 null lists are equivelent. You may want to change this. return true; } else { return false; } } if(b==null) { return false; } Map<Object, Integer> tempMap = new HashMap<>(); for(Object element : a) { Integer currentCount = tempMap.get(element); if(currentCount == null) { tempMap.put(element, 1); } else { tempMap.put(element, currentCount+1); } } for(Object element : b) { Integer currentCount = tempMap.get(element); if(currentCount == null) { return false; } else { tempMap.put(element, currentCount-1); } } for(Integer count : tempMap.values()) { if(count != 0) { return false; } } return true; } 

运行时间是O(n),因为我们正在O(2 * n)插入到散列映射中,并且O(3 * n)散列映射select。 我没有完全testing这个代码,所以要小心:)

 //Returns true: listsAreEquivelent(Arrays.asList("A","A","B"),Arrays.asList("B","A","A")); listsAreEquivelent(null,null); //Returns false: listsAreEquivelent(Arrays.asList("A","A","B"),Arrays.asList("B","A","B")); listsAreEquivelent(Arrays.asList("A","A","B"),Arrays.asList("A","B")); listsAreEquivelent(Arrays.asList("A","A","B"),null); 

尝试这个版本,不要求命令是相同的,但支持具有相同的值的多个。 它们只有在每个数值相同时才匹配。

 public boolean arraysMatch(List<String> elements1, List<String> elements2) { // Optional quick test since size must match if (elements1.size() != elements2.size()) { return false; } List<String> work = newArrayList(elements2); for (String element : elements1) { if (!work.remove(element)) { return false; } } return work.isEmpty(); } 

如果您正在使用(或者很高兴使用)Apache Commons Collections,那么可以使用CollectionUtils.isEqualCollection ,“如果给定的集合包含完全相同的元素,并且具有完全相同的基数,则返回true”。

两个列表具有相同元素但sorting不同的情况下的解决scheme:

 public boolean isDifferentLists(List<Integer> listOne, List<Integer> listTwo) { if(isNullLists(listOne, listTwo)) { return false; } if (hasDifferentSize(listOne, listTwo)) { return true; } List<Integer> listOneCopy = Lists.newArrayList(listOne); List<Integer> listTwoCopy = Lists.newArrayList(listTwo); listOneCopy.removeAll(listTwoCopy); return CollectionUtils.isNotEmpty(listOneCopy); } private boolean isNullLists(List<Integer> listOne, List<Integer> listTwo) { return listOne == null && listTwo == null; } private boolean hasDifferentSize(List<Integer> listOne, List<Integer> listTwo) { return (listOne == null && listTwo != null) || (listOne != null && listTwo == null) || (listOne.size() != listTwo.size()); } 

List上的equals方法会这样做,List是有序的,所以相等的两个List必须有相同顺序的元素。

 return list1.equals(list2); 
 list1.equals(list2); 

如果你的列表包含一个自定义的类MyClass,那么这个类必须重写equals函数。

  class MyClass { int field=0; @0verride public boolean equals(Object other) { if(this==other) return true; if(other==null || !(other instanceof MyClass)) return false; return this.field== MyClass.class.cast(other); } } 

注意:如果你想在java.util.Set而不是java.util.List上testingequals,那么你的对象必须覆盖hashCode函数。

你可以使用Apache的org.apache.commons.collections库: http : //commons.apache.org/collections/apidocs/org/apache/commons/collections/ListUtils.html

 public static boolean isEqualList(java.util.Collection list1, java.util.Collection list2) 

示例代码:

 public static '<'T'>' boolean isListDifferent(List'<'T'>' previousList, List'<'T'>' newList) { int sizePrevoisList = -1; int sizeNewList = -1; if (previousList != null && !previousList.isEmpty()) { sizePrevoisList = previousList.size(); } if (newList != null && !newList.isEmpty()) { sizeNewList = newList.size(); } if ((sizePrevoisList == -1) && (sizeNewList == -1)) { return false; } if (sizeNewList != sizePrevoisList) { return true; } List n_prevois = new ArrayList(previousList); List n_new = new ArrayList(newList); try { Collections.sort(n_prevois); Collections.sort(n_new); } catch (ClassCastException exp) { return true; } for (int i = 0; i < sizeNewList; i++) { Object obj_prevois = n_prevois.get(i); Object obj_new = n_new.get(i); if (obj_new.equals(obj_prevois)) { // Object are same } else { return true; } } return false; } 

检查两个列表不是空值。 如果它们的大小不同,那么这些列表是不相等的。 构build包含列表元素作为键和其重复值作为值的映射并比较映射。

假设,如果两个列表都是空值,我认为它们是平等的。

 private boolean compareLists(List<?> l1, List<?> l2) { if (l1 == null && l2 == null) { return true; } else if (l1 == null || l2 == null) { return false; } if (l1.size() != l2.size()) { return false; } Map<?, Integer> m1 = toMap(l1); Map<?, Integer> m2 = toMap(l2); return m1.equals(m2); } private Map<Object, Integer> toMap(List<?> list) { //Effective size, not to resize in the future. int mapSize = (int) (list.size() / 0.75 + 1); Map<Object, Integer> map = new HashMap<>(mapSize); for (Object o : list) { Integer count = map.get(o); if (count == null) { map.put(o, 1); } else { map.put(o, ++count); } } System.out.println(map); return map; } 

请注意,方法等于应该正确定义这些对象。 https://stackoverflow.com/a/24814634/4587961

这取决于你正在使用什么具体的List类。 抽象类AbstractCollection有一个名为containsAll(Collection)的方法,它接受另一个集合(List是一个集合),并且:

如果此集合包含指定集合中的所有元素,则返回true。

所以如果一个ArrayList被传入,你可以调用这个方法来看看它们是否完全一致。

  List foo = new ArrayList(); List bar = new ArrayList(); String str = "foobar"; foo.add(str); bar.add(str); foo.containsAll(bar); 

containsAll()的原因是因为它遍历第一个列表,在第二个列表中寻找匹配。 所以,如果他们没有秩序equals()将不会拿起它。

编辑:我只想在这里提出执行提供的各种选项的分期运行时间的评论。 运行时间很重要吗? 当然。 这是你唯一应该考虑的事情吗? 没有。

从列表中复制EVERY单个元素到其他列表的花费需要时间,而且它占用了大量的内存(有效地使内存翻倍)。

因此,如果您的JVM中的内存不是问题(通常应该是这个问题),那么您仍然需要考虑将两个列表中的每个元素复制到两个TreeSet中所需的时间。 记住它正在对每个元素进行sorting。

我最后的build议? 您需要考虑数据集以及数据集中的元素数量,以及数据集中每个对象的大小,然后才能在此做出正确的决定。 与他们一起玩,每一个创build一个,看看哪一个运行得更快。 这是一个很好的练习。