Elementos comunes en dos listas

95

Tengo dos ArrayListobjetos con tres enteros cada uno. Quiero encontrar una manera de devolver los elementos comunes de las dos listas. ¿Alguien tiene una idea de cómo puedo lograr esto?

Zenitis
fuente

Respuestas:

161

Utilice Collection#retainAll().

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

Si desea evitar que los cambios se vean afectados listA, debe crear uno nuevo.

List<Integer> common = new ArrayList<Integer>(listA);
common.retainAll(listB);
// common now contains only the elements which are contained in listA and listB.
BalusC
fuente
RetainAll devuelve una nueva lista? Traté de almacenar la salida de retención en una nueva lista como esa tempList.addAll (listA.retainAll (listB)); pero no funciona
zenitis
1
Como se responde en el enlace de atrás Collection#retainAll()y los comentarios en los fragmentos de código, no, no es así. Los cambios se reflejan en la lista a la que está llamando al método.
BalusC
El problema es que la lista común se inicializa con el tamaño 3, luego intenta cambiar su tamaño devolviendo solo uno o dos elementos. Intento lo que sugieres y me devuelve la excepción fuera de los límites.
zenitis
En este enfoque, no podré hacer coincidir el número de ocurrencia del elemento ... digamos, por ejemplo, listA {2,3,5} y listB {5 5}, si lo hago listB.retainAll (listA) , listB ahora tendrá {5,5} ...... Quiero mi resultado final después de comparar listA y listB como {5}. Por favor sugiera cómo podemos lograr esto
NANCY
1
Si se hace con una mala elección del objeto de colección, podría generar una UnsupportedOperationException. El ejemplo anterior con ArrayList funciona, por supuesto.
demongolem
39

Puede utilizar establecer operaciones de intersección con sus ArrayListobjetos.

Algo como esto:

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

Ahora, l3debería tener solo elementos comunes entre l1y l2.

CONSOLE OUTPUT
l1 == [1, 2, 3]
l2 == [4, 2, 3]
l3 == [2, 3]
Pablo Santa Cruz
fuente
6
Tenga en cuenta que de esta manera los cambios también se reflejan l2. Probablemente quisiste decir en su List<Integer> l3 = new ArrayList<Integer>(l2);lugar.
BalusC
El problema se complica un poco si digamos que l1 tiene 2 de un elemento y l2 tiene 3 de ese mismo elemento. RetenerAll devuelve pone 3 de ese elemento en l3 aunque solo esté contenido dos veces en l1.
demongolem
35

¿Por qué reinventar la rueda? Utilice colecciones comunes :

CollectionUtils.intersection(java.util.Collection a, java.util.Collection b)
dkb
fuente
Esta es una gran solución, sin embargo, como mencioné anteriormente, tiene un comportamiento diferente al retainAll()de los elementos repetidos. Es probable que uno sea correcto y otro incorrecto dependiendo de cómo aborde el problema.
demongolem
18

Usando el Stream.filter()método de Java 8 en combinación con 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
fuente
4
Contiene parece que sería una operación O (n), que se llamaría n veces, a menos que el compilador haga algo inteligente. ¿Alguien sabe si lo anterior se ejecuta en tiempo lineal o cuadrático?
Regorsmitz
1
¡Sería una operación * n!
Lakshmikant Deshpande
5

ingrese la descripción de la imagen aquí

            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
fuente
Si bien este código puede responder a la pregunta, proporcionar un contexto adicional sobre cómo y / o por qué resuelve el problema mejoraría el valor de la respuesta a largo plazo.
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

Salida [1, 5]

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

Puede obtener los elementos comunes entre dos listas usando el método "retenerAll". Este método eliminará todos los elementos no coincidentes de la lista a la que se aplica.

Ex.: list.retainAll(list1);

En este caso de la lista, todos los elementos que no están en list1 serán eliminados y solo quedarán aquellos que son comunes entre list y 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);

Salida:

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

NOTA: Después de aplicar retenerAll en la lista, la lista contiene un elemento común entre list y list1.

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

considerar dos listas L1 y L2

Usando Java8 podemos encontrarlo fácilmente

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

AVN
fuente
1

En caso de que quieras hacerlo tú mismo ...

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
fuente
1
El OP estaba pidiendo una forma de encontrar qué elementos eran comunes, no cuántos elementos comunes hay.
Brendon Dugan
@BrendonDugan - Eso es lo que hace este código. La lista commonscontiene los elementos comunes. El segundo bucle for los imprime en la consola. No veo dónde el código está contando los elementos comunes.
Ajoy Bhatia
@AjoyBhatia: cuando hice mi comentario (en 2013), el código solo devolvió un recuento de elementos comunes.
Brendon Dugan
@BrendonDugan Oh, está bien. Lo siento por eso. Debo tener en cuenta que la respuesta se puede editar en su lugar, pero los comentarios generalmente se dejan como están, en orden cronológico :-)
Ajoy Bhatia
0

Algunas de las respuestas anteriores son similares pero no iguales, así que publíquelas como una nueva respuesta.

Solución:
1. Use HashSet para contener los elementos que deben eliminarse
2. Agregue todos los elementos de list1 a HashSet
3. Repita list2 y elimine elementos de un HashSet que están presentes en list2 ==> que están presentes tanto en list1 como en list2
4 . Ahora itere sobre HashSet y elimine elementos de list1 (ya que hemos agregado todos los elementos de list1 al conjunto), finalmente, list1 tiene todos los elementos comunes
Nota: Podemos agregar todos los elementos de list2 y en una tercera iteración, debemos eliminar elementos de lista 2.

Complejidad temporal: O (n)
Complejidad espacial: 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));

salida:

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