Java 查找两个不同列表是否包含完全相同元素的简单方法?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1075656/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Simple way to find if two different lists contain exactly the same elements?
提问by Grundlefleck
What is the simplest way to find if two Lists contain exactly the same elements, in the standard Java libraries?
在标准 Java 库中,查找两个 List 是否包含完全相同的元素的最简单方法是什么?
It shouldn't matter if the two Lists are the same instance or not, and it shouldn't matter if the type parameter of the Lists are different.
两个Lists是否为同一个实例无关紧要,Lists的类型参数是否不同也无关紧要。
e.g.
例如
List list1
List<String> list2;
// ... construct etc
list1.add("A");
list2.add("A");
// the function, given these two lists, should return true
There's probably something staring me in the face I know :-)
我知道可能有什么东西盯着我看:-)
EDIT: To clarify, I was looking for the EXACT same elements and number of elements, in order.
编辑:为了澄清,我正在寻找完全相同的元素和元素数量,按顺序。
采纳答案by Laurence Gonsalves
If you care about order, then just use the equals method:
如果您关心顺序,那么只需使用 equals 方法:
list1.equals(list2)
From the javadoc:
从javadoc:
Compares the specified object with this list for equality. Returns true 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 equal. (Two elements e1 and e2 are equal if (e1==null ? e2==null : e1.equals(e2)).) 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 List interface.
比较指定的对象与此列表是否相等。当且仅当指定的对象也是一个列表,两个列表的大小相同,并且两个列表中所有对应的元素对都相等时,才返回 true。(如果 (e1==null ? e2==null : e1.equals(e2)),两个元素 e1 和 e2 相等。)换句话说,如果两个列表以相同的顺序包含相同的元素,则它们被定义为相等. 此定义可确保 equals 方法在 List 接口的不同实现中正常工作。
If you want to check independent of order, you could copy all of the elements to Sets and use equals on the resulting Sets:
如果您想独立于顺序进行检查,您可以将所有元素复制到 Sets 并在结果 Sets 上使用 equals:
public static <T> boolean listEqualsIgnoreOrder(List<T> list1, List<T> list2) {
return new HashSet<>(list1).equals(new HashSet<>(list2));
}
A limitation of this approach is that it not only ignores order, but also frequency of duplicate elements. For example, if list1
was ["A", "B", "A"] and list2
was ["A", "B", "B"] the Set
approach would consider them to be equal.
这种方法的一个限制是它不仅忽略了顺序,而且忽略了重复元素的频率。例如,如果list1
是 ["A", "B", "A"] 并且list2
是 ["A", "B", "B"],则该Set
方法会认为它们是相等的。
If you need to be insensitive to order but sensitive to the frequency of duplicates you can either:
如果您需要对订单不敏感但对重复的频率敏感,您可以:
- sort both lists (or copies) before comparing them, as done in this answer to another question
- or copy all elements to a Multiset
- 在比较它们之前对两个列表(或副本)进行排序,如this answer to another question中所做的那样
- 或将所有元素复制到Multiset
回答by Jeremy Smyth
回答by daveb
The equals method on List will do this, Lists are ordered, so to be equal two Lists must have the same elements in the same order.
List 上的 equals 方法将执行此操作,List 是有序的,因此要相等,两个 List 必须具有相同顺序的相同元素。
return list1.equals(list2);
回答by Pierre
list1.equals(list2);
If your list contains a custom Class MyClass, this class must override the equals
function.
如果您的列表包含自定义 Class 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).field;
}
}
Note :if you want to test equals on a java.util.Set rather than a java.util.List
, then your object must override the hashCode
function.
注意:如果您想在 java.util.Set 而不是 a 上测试 equals java.util.List
,那么您的对象必须覆盖该hashCode
函数。
回答by amischiefr
It depends on what concrete List class you are using. The abstract class AbstractCollection has a method called containsAll(Collection) that takes another collection ( a List is a collection) and:
这取决于您使用的具体 List 类。抽象类 AbstractCollection 有一个名为 containsAll(Collection) 的方法,它接受另一个集合(一个 List 是一个集合)并且:
Returns true if this collection contains all of the elements in the specified collection.
如果此集合包含指定集合中的所有元素,则返回 true。
So if an ArrayList is being passed in you can call this method to see if they are exactly the same.
因此,如果传入的是 ArrayList,您可以调用此方法来查看它们是否完全相同。
List foo = new ArrayList();
List bar = new ArrayList();
String str = "foobar";
foo.add(str);
bar.add(str);
foo.containsAll(bar);
The reason for containsAll() is because it iterates through the first list looking for the match in the second list. So if they are out of order equals() will not pick it up.
containsAll() 的原因是因为它遍历第一个列表以查找第二个列表中的匹配项。因此,如果它们出现故障,equals() 将不会将其捡起。
EDIT: I just want to make a comment here about the amortized running time of performing the various options being offered. Is running time important? Sure. Is it the only thing you should consider? No.
编辑:我只想在这里评论一下执行所提供的各种选项的摊销运行时间。运行时间重要吗?当然。这是您唯一应该考虑的事情吗?不。
The cost of copying EVERY single element from your lists into other lists takes time, and it also takes up a good chunk of memory (effectively doubling the memory you are using).
将列表中的每个元素复制到其他列表的成本需要时间,并且它也占用大量内存(有效地使您使用的内存增加一倍)。
So if memory in your JVM isn't a concern (which it should generally be) then you still need to consider the time it takes to copy every element from two lists into two TreeSets. Remember it is sorting every element as it enters them.
因此,如果您的 JVM 中的内存不是问题(通常应该是),那么您仍然需要考虑将两个列表中的每个元素复制到两个 TreeSet 所需的时间。请记住,它是在每个元素进入它们时对其进行排序。
My final advice? You need to consider your data set and how many elements you have in your data set, and also how large each object in your data set is before you can make a good decision here. Play around with them, create one each way and see which one runs faster. It's a good exercise.
我最后的建议?您需要考虑您的数据集以及您的数据集中有多少元素,以及您的数据集中每个对象的大小,然后才能在这里做出正确的决定。和他们一起玩,每条路都创建一个,看看哪个跑得更快。这是一个很好的锻炼。
回答by Tom
I posted a bunch of stuff in comments I think it warrants its own answer.
我在评论中发布了一堆东西,我认为它值得自己回答。
As everyone says here, using equals() depends on the order. If you don't care about order, you have 3 options.
正如这里的每个人所说,使用 equals() 取决于顺序。如果您不关心订单,您有 3 个选择。
Option 1
选项1
Use containsAll()
. This option is not ideal, in my opinion, because it offers worst case performance, O(n^2).
使用containsAll()
. 在我看来,这个选项并不理想,因为它提供了最坏情况下的性能,O(n^2)。
Option 2
选项 2
There are two variations to this:
这有两种变体:
2a)If you don't care about maintaining the order ofyour lists... use Collections.sort()
on both list. Then use the equals()
. This is O(nlogn), because you do two sorts, and then an O(n) comparison.
2a)如果您不关心维护列表的顺序...Collections.sort()
在两个列表上都使用。然后使用equals()
. 这是 O(nlogn),因为您执行两种排序,然后进行 O(n) 比较。
2b)If you need to maintain the lists' order, you can copy both lists first. THEN you can use solution 2aon both the copied lists. However this might be unattractive if copying is very expensive.
2b)如果您需要维护列表的顺序,您可以先复制两个列表。然后您可以在两个复制的列表上使用解决方案2a。但是,如果复制非常昂贵,这可能没有吸引力。
This leads to:
这将导致:
Option 3
选项 3
If your requirements are the same as part 2b, but copying is too expensive. You can use a TreeSet to do the sorting for you. Dump each list into its own TreeSet. It will be sorted in the set, and the original lists will remain intact. Then perform an equals()
comparison on both TreeSet
s. The TreeSets
s can be built in O(nlogn) time, and the equals()
is O(n).
如果您的要求与第2b部分相同,但复制成本太高。您可以使用 TreeSet 为您进行排序。将每个列表转储到它自己的 TreeSet 中。它将在集合中排序,原始列表将保持不变。然后equals()
对两者进行比较TreeSet
。所述TreeSets
s时,可以建在O(nlogn)时间,并且equals()
为O(n)。
Take your pick :-).
随意选择:-)。
EDIT:I almost forgot the same caveat that Laurence Gonsalvespoints out. The TreeSet implementation will eliminate duplicates. If you care about duplicates, you will need some sort of sorted multiset.
编辑:我几乎忘记了Laurence Gonsalves指出的同样的警告。TreeSet 实现将消除重复项。如果您关心重复项,您将需要某种排序的多重集。
回答by David Zhao
You can use Apache's org.apache.commons.collections library: http://commons.apache.org/collections/apidocs/org/apache/commons/collections/ListUtils.html
您可以使用 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)
回答by Jaydip Halake
Sample code:
示例代码:
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;
}
回答by Lee Meador
Try this version which does not require order to be the same but does support having multiple of the same value. They match only if each has the same quantity of any value.
试试这个版本,它不需要相同的顺序,但支持具有多个相同的值。它们仅在每个具有相同数量的任何值时才匹配。
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();
}
回答by Andrew
I know this is an old thread, but none of the other answers fully solved my use case (I guess Guava Multiset might do the same, but there is no example here). Please excuse my formatting. I am still new to posting on stack exchange. Additionally let me know if there are any errors
我知道这是一个旧线程,但其他答案都没有完全解决我的用例(我猜 Guava Multiset 可能会这样做,但这里没有示例)。请原谅我的格式。我仍然是在堆栈交换上发帖的新手。另外让我知道是否有任何错误
Lets say you have List<T>
a and List<T>
b and you want to check if they are equal with the following conditions:
假设您有List<T>
a 和List<T>
b 并且您想检查它们是否与以下条件相等:
1) O(n) expected running time
2) Equality is defined as: For all elements in a or b, the number of times the element occurs in a is equal to the number of times the element occurs in b. Element equality is defined as T.equals()
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;
}
Running time is O(n) because we are doing O(2*n) insertions into a hashmap and O(3*n) hashmap selects. I have not fully tested this code, so beware :)
运行时间是 O(n),因为我们正在对 hashmap 进行 O(2*n) 次插入和 O(3*n) 次 hashmap 选择。我还没有完全测试这段代码,所以要小心:)
//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);