两个列表中的共同元素

128

我有两个包含三个整数的ArrayList对象。我想找到一种返回这两个列表中共同元素的方法。请问是否有任何想法可以实现这个功能?

15个回答

193
使用{{link1:Collection#retainAll()}}。
listA.retainAll(listB);
// listA now contains only the elements which are also contained in listB.

如果你想避免对 listA 的更改,那么你需要创建一个新的列表。
List<Integer> common = new ArrayList<>(listA);
common.retainAll(listB);
// common now contains only the elements which are contained in listA and listB.

如果你喜欢流,最好的做法是在另一个列表上使用 Stream#filter()Collection#contains()
List<Integer> common = listA.stream().filter(listB::contains).toList();
// common now contains only the elements which are contained in listA and listB.

它只是慢了至少两倍。


1
正如在Collection#retainAll()的链接和代码片段的注释中所回答的那样,不会。更改将反映在您调用该方法的列表中。 - BalusC
在这种方法中,我将无法匹配元素的出现次数......例如,listA {2,3,5} 和 listB {5 5},如果我执行 listB.retainAll(listA),listB 现在将变为 {5,5}......我希望在比较 listA 和 listB 后得到的最终结果为 {5}。请建议如何实现。 - NANCY
@NANCY Commons Collections 的解决方案应该可以按照您的意愿工作,但不包括 retainAll() 方法。 - demongolem
1
如果使用不当的集合对象,可能会抛出UnsupportedOperationException异常。当然,上面使用ArrayList的例子是可行的。 - demongolem
非常感谢这个。 - s_bei
显示剩余2条评论

45
你可以使用集合交集操作来处理你的 ArrayList 对象。
类似这样的操作:
List<Integer> l1 = new ArrayList<Integer>();

l1.add(1);
l1.add(2);
l1.add(3);

List<Integer> l2= new ArrayList<Integer>();
l2.add(4);
l2.add(2);
l2.add(3);

System.out.println("l1 == "+l1);
System.out.println("l2 == "+l2);

List<Integer> l3 = new ArrayList<Integer>(l2);
l3.retainAll(l1);

    System.out.println("l3 == "+l3);

现在,l3 应该只包含 l1l2 中共同的元素。

CONSOLE OUTPUT
l1 == [1, 2, 3]
l2 == [4, 2, 3]
l3 == [2, 3]

7
请注意,这种方法会同时反映在 l2 中所做的更改。您可能想要说的是 List<Integer> l3 = new ArrayList<Integer>(l2); - BalusC
如果说l1有2个元素,而l2有3个相同的元素,那么问题就会变得有点混乱。retainAll返回将该元素的3个副本放入l3中,即使它在l1中只包含两次。 - demongolem

44

为什么要重复造轮子?使用Commons Collections

CollectionUtils.intersection(java.util.Collection a, java.util.Collection b)

1
这是一个很好的解决方案,但正如我上面提到的,它在重复元素上的行为与retainAll()不同。因此,根据您如何处理问题,可能有一个是正确的,而另一个是错误的。 - demongolem

26

使用Java 8的Stream.filter()方法与List.contains()方法结合:

import static java.util.Arrays.asList;
import static java.util.stream.Collectors.toList;

/* ... */

List<Integer> list1 = asList(1, 2, 3, 4, 5);
List<Integer> list2 = asList(1, 3, 5, 7, 9);
    
List<Integer> common = list1.stream().filter(list2::contains).collect(toList());

4
Contains看起来像是一个O(n)的操作,会被调用n次,除非编译器做了一些聪明的事情。有人知道上述代码运行时间是线性还是二次方吗? - Regorsmitz
1
这将是一个n*n的操作! - Lakshmikant Deshpande
2
读者注意:在Java 16+中,将.collect(Collectors.toList())替换为更短的.toList()Stream上的新方法)。 - Basil Bourque

6

考虑两个列表 L1 和 L2

使用 Java8 我们可以轻松地找到它

L1.stream().filter(L2::contains).collect(Collectors.toList())


5

您可以使用"retainAll"方法获取两个列表之间的共同元素。该方法将从应用于的列表中删除所有不匹配的元素。

Ex.: list.retainAll(list1);

在这个列表中,所有不在list1中的元素都将被删除,只有那些list和list1之间共同的元素才会保留。
List<Integer> list = new ArrayList<>();
list.add(10);
list.add(13);
list.add(12);
list.add(11);

List<Integer> list1 = new ArrayList<>();
list1.add(10);
list1.add(113);
list1.add(112);
list1.add(111);
//before retainAll
System.out.println(list);
System.out.println(list1);
//applying retainAll on list
list.retainAll(list1);
//After retainAll
System.out.println("list::"+list);
System.out.println("list1::"+list1);

输出:

[10, 13, 12, 11]
[10, 113, 112, 111]
list::[10]
list1::[10, 113, 112, 111]

注意:在对列表执行retainAll操作后,列表将包含列表和list1之间的公共元素。


“intersection”是一种方法,我们从列表1中删除所有共同的元素并保留唯一的元素。 - Tarnished-Coder

5

enter image description here

List<String> lista =new ArrayList<String>();
List<String> listb =new ArrayList<String>();

lista.add("Isabella");
lista.add("Angelina");
lista.add("Pille");
lista.add("Hazem");

listb.add("Isabella");
listb.add("Angelina");
listb.add("Bianca");

// Create an aplusb list which will contain both list (list1 and list2) in which common element will occur twice 
List<String> listapluslistb =new ArrayList<String>(lista);    
listapluslistb.addAll(listb);
                
// Create an aunionb set which will contain both list (list1 and list2) in which common element will occur once
Set<String> listaunionlistb =new HashSet<String>(lista);
listaunionlistb.addAll(listb);
                
for(String s:listaunionlistb)
{
    listapluslistb.remove(s);
}
System.out.println(listapluslistb);

虽然这段代码可能回答了问题,但提供关于它是如何解决问题的方式和/或原因的额外上下文会提高答案的长期价值。 - Michael Parker

4
public <T> List<T> getIntersectOfCollections(Collection<T> first, Collection<T> second) {
        return first.stream()
                .filter(second::contains)
                .collect(Collectors.toList());
    }

2
    // Create two collections:
    LinkedList<String> listA =  new LinkedList<String>();
    ArrayList<String> listB =  new ArrayList<String>();

    // Add some elements to listA:
    listA.add("A");
    listA.add("B");
    listA.add("C");
    listA.add("D");

    // Add some elements to listB:
    listB.add("A");
    listB.add("B");
    listB.add("C");

    // use 

    List<String> common = new ArrayList<String>(listA);
    // use common.retainAll

    common.retainAll(listB);

    System.out.println("The common collection is : " + common);

1
如果您想自己做的话...
List<Integer> commons = new ArrayList<Integer>();

for (Integer igr : group1) {
    if (group2.contains(igr)) {
        commons.add(igr);
    }
}

System.out.println("Common elements are :: -");
for (Integer igr : commons) {
    System.out.println(" "+igr);
}

1
OP正在寻找一种查找共同元素的方法,而不是共同元素的数量。 - Brendon Dugan
@BrendonDugan - 这段代码的作用就是这样。列表 commons 包含了共同元素。第二个 for 循环将它们打印到控制台上。我没有看到代码在哪里计算共同元素的数量。 - Ajoy Bhatia
@AjoyBhatia - 当我在2013年发表评论时,代码只返回了共同元素的计数。 - Brendon Dugan
@BrendonDugan 哦,好的。对此我感到抱歉。我应该记住答案可以直接编辑,但评论通常按时间顺序保留不变 :-) - Ajoy Bhatia

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接