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?

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.

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]

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)

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

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

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]


-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.


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

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

3

considere duas listas L1 e L2

Usando Java8, podemos descobrir facilmente

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


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

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]
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.