Compruebe si una lista contiene elementos de la otra


105

Tengo dos listas con diferentes objetos en ellas.

List<Object1> list1;
List<Object2> list2;

Quiero verificar si el elemento de list1 existe en list2, según un atributo específico (Object1 y Object2 tienen (entre otros), un atributo mutuo (con tipo Long), llamado attributeSame).

ahora mismo, lo hago así:

boolean found = false;
for(Object1 object1 : list1){
   for(Object2 object2: list2){
       if(object1.getAttributeSame() == object2.getAttributeSame()){
           found = true;
           //also do something
       }
    }
    if(!found){
        //do something
    }
    found = false;
}

Pero creo que hay una manera mejor y más rápida de hacer esto :) ¿Alguien puede proponerlo?

¡Gracias!


en primer lugar, cuando establece found = true; luego simplemente rompa; o salir del circuito
jsist

stackoverflow.com/questions/5187888/… . Por otra parte, para la búsqueda rápida intente utilizar búsqueda binaria y cambiar su DS a la habitación de la situación ...
jsist

¿comparten un padre común además de Object?
Woot4Moo

@ Woot4Moo no, no lo hacen
Ned

Respuestas:


219

Si solo necesita probar la igualdad básica, esto se puede hacer con el JDK básico sin modificar las listas de entrada en una línea

!Collections.disjoint(list1, list2);

Si necesita probar una propiedad específica, es más difícil. Recomendaría, por defecto,

list1.stream()
   .map(Object1::getProperty)
   .anyMatch(
     list2.stream()
       .map(Object2::getProperty)
       .collect(toSet())
       ::contains)

... que recopila los distintos valores list2y prueba la list1presencia de cada valor .


1
¿No devolverá siempre falso ya que ambos son 2 objetos diferentes?
Venki

2
¿Mmm no? Pruebas disjuntas si no hay objetos iguales () entre sí entre las dos colecciones.
Louis Wasserman

13
Además, tenga en cuenta que, para las listas, será O (n * m); si está dispuesto a copiar list1en a Setantes de comparar, obtendrá O (n) + O (m), es decir, O (n + m), a costa de algo de RAM adicional; es cuestión de elegir entre velocidad o memoria.
Haroldo_OK

Esto funcionaría sólo si "Lista <Persona> lista1; Lista <Persona> lista2" pero no en dos objetos o tipos de datos diferentes como Lista <Persona> list1; Lista <Empleado> list2.
whoami

Por supuesto, esto no funcionará para esos escenarios @Zephyr, para la pregunta formulada, funciona perfectamente siempre que tenga implementados los iguales correctos. eso es todo!
Syed Siraj Uddin

38

Puede utilizar Apache Commons CollectionUtils :

if(CollectionUtils.containsAny(list1,list2)) {  
    // do whatever you want
} else { 
    // do other thing 
}  

Esto supone que ha sobrecargado correctamente la funcionalidad de iguales para sus objetos personalizados.


9
Han pasado 4 años y también llamo explícitamente el paquete y la función.
Woot4Moo

1
Downvote para Apache bien común, cuando hay una única solución JDK
ohcibi

9
@ohcibi Java también tiene un registrador incorporado, debe votar en contra de las personas que sugieren usar Log4j y Log4j2 mientras lo hace.
Woot4Moo

1
@ Woot4Moo, depende. No hay razón para rechazar la votación si hay una razón para usar Log4j para resolver el problema de los OP. En este caso, los comunes de apache serían simplemente inútiles como en el 99% de las respuestas que sugieren los comunes de apache.
ohcibi

1
@ohcibi, pero si ya está usando Apache commons, entonces no es realmente grande. Esta fue una buena respuesta.
vab2048

19

Para acortar la lógica de Narendra, puede usar esto:

boolean var = lis1.stream().anyMatch(element -> list2.contains(element));

3
esta respuesta es subestimada.
Kervvv

Puedes acortarlo un poco más si quieres:list1.stream().anyMatch(list2::contains);
tarka

9

Hay un método para Collectionnombrar retainAllpero que tiene algunos efectos secundarios para su referencia

Conserva solo los elementos de esta lista que están contenidos en la colección especificada (operación opcional). En otras palabras, elimina de esta lista todos sus elementos que no están contenidos en la colección especificada.

Verdadero si esta lista cambió como resultado de la llamada

Es como

boolean b = list1.retainAll(list2);

5

La respuesta de Loius es correcta, solo quiero agregar un ejemplo:

listOne.add("A");
listOne.add("B");
listOne.add("C");

listTwo.add("D");
listTwo.add("E");
listTwo.add("F");      

boolean noElementsInCommon = Collections.disjoint(listOne, listTwo); // true

1
Creo que si agrega el elemento 'A' a la segunda lista listTwo.add ("A"); aunque Collections.disjoint (listOne, listTwo); devuelve verdadero.
Sairam Kukadala

2

forma más rápida requerirá espacio adicional.

Por ejemplo:

  1. ponga todos los elementos en una lista en un HashSet (debe implementar la función hash usted mismo para usar object.getAttributeSame ())

  2. Revise la otra lista y verifique si algún elemento está en el HashSet.

De esta forma, cada objeto se visita como máximo una vez. y HashSet es lo suficientemente rápido para verificar o insertar cualquier objeto en O (1).


2

Según JavaDoc para .contains(Object obj):

Devuelve verdadero si esta lista contiene el elemento especificado. Más formalmente, devuelve verdadero si y solo si esta lista contiene al menos un elemento e tal que (o == null? E == null: o.equals (e)).

Entonces, si anula su .equals()método para su objeto dado, debería poder hacer:if(list1.contains(object2))...

Si los elementos serán únicos (es decir. Tener diferentes atributos) que podría invalidar la .equals()e .hashcode()y almacenar todo en HashSets. Esto le permitirá comprobar si uno contiene otro elemento en tiempo constante.


2

para hacerlo más rápido, puede agregar un descanso; de esa manera, el bucle se detendrá si se encuentra establecido en verdadero:

boolean found = false;
for(Object1 object1 : list1){
   for(Object2 object2: list2){
       if(object1.getAttributeSame() == object2.getAttributeSame()){
           found = true;
           //also do something  
           break;
       }
    }
    if(!found){
        //do something
    }
    found = false;
}

Si tuviera mapas en lugar de listas con como claves el atributo Igual, podría verificar más rápido un valor en un mapa si hay un valor correspondiente en el segundo mapa o no.


Hola Tom, ¡gracias por darte cuenta! Sí, olvidé "romper" mientras escribía. Pero estaba pensando que tal vez haya algún algoritmo, o debería cambiar estas listas por otras colecciones.
Ned

¿No hay nada mejor que O (n * m)?
Woot4Moo

.getAttributeSame ()?
Maveň ツ

No se proporciona la implementación para el método getAttributeSame () de Object1 y Object2, pero tampoco son relevantes para la pregunta y la respuesta; simplemente devuelve un atributo (attributeSame, un Long) que tienen ambas clases.
Tom

0

¿Puede definir el tipo de datos que tiene? ¿es big data? esta ordenado? Creo que debe considerar diferentes enfoques de eficiencia en función de los datos.

Por ejemplo, si sus datos son grandes y no están clasificados, puede intentar iterar las dos listas juntas por índice y almacenar cada atributo de lista en otro asistente de lista. luego podría verificar los atributos actuales en las listas de ayuda.

buena suerte

editado: y no recomendaría sobrecargar iguales. es peligroso y probablemente en contra de su objeto oop significado.



0

Con java 8, podemos hacer lo siguiente para verificar si una lista contiene algún elemento de otra lista

boolean var = lis1.stream().filter(element -> list2.contains(element)).findFirst().isPresent();

0

Si desea verificar si un elemento existe en una lista, use el método contiene.

if (list1.contains(Object o))
{
   //do this
}
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.