Elementos comuns em duas listas

95

Tenho dois ArrayListobjetos com três inteiros cada. Quero encontrar uma maneira de retornar os elementos comuns das duas listas. Alguém tem ideia de como posso conseguir isso?

zenite
fonte

Respostas:

161

Use Collection#retainAll().

listA.retainAll(listB);
// listA now contains only the elements which are also contained in listB.

Se você quiser evitar que as alterações sejam afetadas em listA, será necessário criar um novo.

List<Integer> common = new ArrayList<Integer>(listA);
common.retainAll(listB);
// common now contains only the elements which are contained in listA and listB.
BalusC
fonte
RetainAll retorna uma nova lista? Tentei armazenar a saída de reter em uma nova lista sth como tempList.addAll (listA.retainAll (listB)); mas não funciona
zenite
1
Conforme respondido no link atrás Collection#retainAll()e os comentários nos trechos de código, não, não importa. As alterações são refletidas na lista na qual você está chamando o método.
BalusC de
O problema é que a lista comum é inicializada com tamanho 3, então você tenta alterar seu tamanho retornando apenas um ou dois elementos. Eu tento o que você sugere e isso me retorna exceção fora dos limites.
zenite
Nesta abordagem, não poderei combinar o número de ocorrência do elemento ... digamos, por exemplo, listaA {2,3,5} e listaB {5 5}, se eu fizer listB.retainAll (listaA) , a lista B agora terá {5,5} ...... Quero meu resultado final depois de comparar a lista A e a lista B como {5}. Por favor, sugira como podemos conseguir isso
NANCY,
1
Se feito com uma escolha inadequada de objeto de coleção, ele pode lançar uma UnsupportedOperationException. O exemplo acima com ArrayList funciona, é claro.
demongolem
39

Você pode usar operações de interseção definidas com seus ArrayListobjetos.

Algo assim:

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

Agora, l3deve haver apenas elementos comuns entre l1e l2.

CONSOLE OUTPUT
l1 == [1, 2, 3]
l2 == [4, 2, 3]
l3 == [2, 3]
Pablo Santa Cruz
fonte
6
Observe que desta forma as alterações também são refletidas l2. Você provavelmente quis dizer em List<Integer> l3 = new ArrayList<Integer>(l2);vez disso.
BalusC de
O problema fica um pouco mais complicado se, digamos, l1 tiver 2 de um elemento e l2 tiver 3 desse mesmo elemento. retémAll retorna coloca 3 daquele elemento em l3, embora ele esteja contido apenas duas vezes em l1.
demongolem
35

Por que reinventar a roda? Use coleções comuns :

CollectionUtils.intersection(java.util.Collection a, java.util.Collection b)
dkb
fonte
Esta é uma ótima solução, porém como mencionei acima, ela tem um comportamento diferente do que retainAll()em elementos repetidos. Portanto, provavelmente um está correto e o outro incorreto, dependendo de como você aborda o problema.
demongolem
18

Usando o Stream.filter()método Java 8 em combinação com 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());
Robby Cornelissen
fonte
4
Contains parece que seria uma operação O (n), que seria chamada n vezes, a menos que o compilador faça algo inteligente. Alguém sabe se o anterior é executado em tempo linear ou quadrático?
Regorsmitz
1
Seria uma operação * n!
Lakshmikant Deshpande
5

insira a descrição da imagem aqui

            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);
Pawan Kumar Baranwal
fonte
Embora este código possa responder à pergunta, fornecer contexto adicional sobre como e / ou por que ele resolve o problema melhoraria o valor da resposta a longo prazo.
Michael Parker
5
List<Integer> listA = new ArrayList<>();
    listA.add(1);
    listA.add(5);
    listA.add(3);
    listA.add(4);   

List<Integer> listB = new ArrayList<>();
    listB.add(1);
    listB.add(5);
    listB.add(6);
    listB.add(7);
System.out.println(listA.stream().filter(listB::contains).collect(Collectors.toList()));


Java 1.8 Stream API Solutions

Produto [1, 5]

Rajeev Ranjan
fonte
-Melhoria podemos definir lista como List <Integer> listA = asList (1, 5, 3, 4); List <Integer> listB = asList (1, 5, 6, 7);
Rajeev Ranjan
4

Você pode obter os elementos comuns entre duas listas usando o método "reterAll". Este método removerá todos os elementos não correspondentes da lista à qual se aplica.

Ex.: list.retainAll(list1);

Neste caso, da lista, todos os elementos que não estão na lista1 serão removidos e ficarão apenas aqueles que são comuns entre a lista e a lista1.

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

Resultado:

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

NOTA: Depois de reterAll aplicado na lista, a lista contém elementos comuns entre lista e lista1.

Vivek Kumar Sihare
fonte
4
public <T> List<T> getIntersectOfCollections(Collection<T> first, Collection<T> second) {
        return first.stream()
                .filter(second::contains)
                .collect(Collectors.toList());
    }
Ruslan Taghiyev
fonte
3
    // 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);
Ryagh
fonte
3

considere duas listas L1 e L2

Usando Java8, podemos descobrir facilmente

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

AVN
fonte
1

Caso você queira fazer isso sozinho ..

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);
}
chetan rami
fonte
1
O OP estava pedindo uma maneira de descobrir quais elementos eram comuns, não quantos elementos comuns existem.
Brendon Dugan
@BrendonDugan - Isso é o que esse código faz. A lista commonscontém os elementos comuns. O segundo for-loop os imprime no console. Não vejo onde o código está contando os elementos comuns.
Ajoy Bhatia
@AjoyBhatia - Quando fiz meu comentário (em 2013), o código retornou apenas uma contagem de elementos comuns.
Brendon Dugan
@BrendonDugan Oh, OK. Me desculpe por isso. Devo ter em mente que a resposta pode ser editada no local, mas os comentários geralmente são deixados como estão, em ordem cronológica :-)
Ajoy Bhatia
0

Algumas das respostas acima são semelhantes, mas não iguais, portanto, publique como uma nova resposta.

Solução:
1. Use o HashSet para manter os elementos que precisam ser removidos
2. Adicione todos os elementos da lista1 ao HashSet
3. itere a lista2 e remova os elementos de um HashSet que estão presentes na lista2 ==> que estão presentes na lista1 e na lista2
4 . Agora itere no HashSet e remova os elementos da lista1 (já que adicionamos todos os elementos da lista1 ao conjunto), finalmente, a lista1 tem todos os elementos comuns
Nota: podemos adicionar todos os elementos da lista2 e em uma terceira iteração, devemos remover os elementos do lista2.

Complexidade de tempo: O (n)
Complexidade do espaço: O (n)

Código:

import com.sun.tools.javac.util.Assert;
import org.apache.commons.collections4.CollectionUtils;

    List<Integer> list1 = new ArrayList<>();
    list1.add(1);
    list1.add(2);
    list1.add(3);
    list1.add(4);
    list1.add(5);

    List<Integer> list2 = new ArrayList<>();
    list2.add(1);
    list2.add(3);
    list2.add(5);
    list2.add(7);
    Set<Integer> toBeRemoveFromList1 = new HashSet<>(list1);
    System.out.println("list1:" + list1);
    System.out.println("list2:" + list2);
    for (Integer n : list2) {
        if (toBeRemoveFromList1.contains(n)) {
            toBeRemoveFromList1.remove(n);
        }
    }
    System.out.println("toBeRemoveFromList1:" + toBeRemoveFromList1);
    for (Integer n : toBeRemoveFromList1) {
        list1.remove(n);
    }
    System.out.println("list1:" + list1);
    System.out.println("collectionUtils:" + CollectionUtils.intersection(list1, list2));
    Assert.check(CollectionUtils.intersection(list1, list2).containsAll(list1));

resultado:

list1:[1, 2, 3, 4, 5]
list2:[1, 3, 5, 7]
toBeRemoveFromList1:[2, 4]
list1:[1, 3, 5]
collectionUtils:[1, 3, 5]
dkb
fonte