Tengo dos ArrayList
s de tipo Answer
(clase propia).
Me gustaría comparar las dos listas para ver si contienen el mismo contenido, pero sin importar el orden.
Ejemplo:
//These should be equal.
ArrayList<String> listA = {"a", "b", "c"}
ArrayList<String> listB = {"b", "c", "a"}
List.equals
establece que dos listas son iguales si contienen el mismo tamaño, contenido y orden de elementos. Quiero lo mismo, pero sin importar el orden.
¿Hay una manera simple de hacer esto? ¿O tendré que hacer un bucle anidado para y verificar manualmente cada índice de ambas listas?
Nota: No puedo cambiarlos ArrayList
a otro tipo de lista, deben permanecer así.
Respuestas:
Puedes ordenar ambas listas usando
Collections.sort()
y luego usar el método igual. Una solución ligeramente mejor es verificar primero si tienen la misma longitud antes de ordenar, si no lo son, entonces no son iguales, luego ordenar y luego usar iguales. Por ejemplo, si tuviera dos listas de cadenas, sería algo así como:fuente
Collections.sort
hace), es decir, pasar una copia.one = new ArrayList<String>(one); two = new ArrayList<String>(two);
para evitar arruinar los argumentos.if(one == null || two == null || one.size() != two.size()){ return false; }
porque ya está comprobando si tanto uno como dos son nulosProbablemente la forma más fácil para cualquier lista sería:
fuente
[a, b, c]
y[c, b, a, b]
se considera que tienen el mismo contenido. Esta respuesta diría que sí, pero podría ser que para el OP no lo hagan (ya que uno contiene un duplicado y el otro no). Por no hablar de los problemas de eficiencia.Colecciones de Apache Commons al rescate una vez más:
Documentos:
fuente
false
? Mira mi respuesta.implementation 'org.apache.commons:commons-collections4:4.3'
me ha dejado con unaCaused by: com.android.builder.dexing.DexArchiveBuilderException: Failed to process
ruta de error .fuente
count
se convierte en negativo, lo que simplifica el cuerpo del bucle aif(!counts.containsKey(item) || --counts.get(item).count < 0) return false;
Además, la tercera bucle podría simplificarse enfor(Count c: counts.values()) if(c.count != 0) return false;
counts
está vacío"), pero no quise oscurecer El punto principal: que el uso de un mapa básicamente convierte esto en un problema de O (N + M), y es el mayor impulso que probablemente obtendrá.Map.merge
números enteros en caja podría ser más simple y más eficiente para la mayoría de los casos de uso. Ver también esta respuesta ...Yo diría que estas respuestas pierden un truco.
Bloch, en su esencial, maravilloso, conciso Java efectivo , dice, en el ítem 47, título "Conozca y use las bibliotecas", "Para resumir, no reinvente la rueda". Y da varias razones muy claras por las que no.
Aquí hay algunas respuestas que sugieren métodos de
CollectionUtils
la biblioteca Apache Commons Collections, pero ninguna ha descubierto la forma más hermosa y elegante de responder esta pregunta :Culpables : es decir, los elementos que no son comunes a ambos
Lists
. Determinar a qué culpables pertenecelist1
y a quélist2
es relativamente sencillo usarCollectionUtils.intersection( list1, culprits )
yCollectionUtils.intersection( list2, culprits )
.Sin embargo, tiende a desmoronarse en casos como {"a", "a", "b"}
disjunction
con {"a", "b", "b"} ... excepto que esto no es una falla del software, pero inherente a la naturaleza de las sutilezas / ambigüedades de la tarea deseada.Siempre puede examinar el código fuente (l. 287) para una tarea como esta, producida por los ingenieros de Apache. Una ventaja de usar su código es que habrá sido probado y probado exhaustivamente, con muchos casos extremos y problemas previstos y tratados. Puede copiar y ajustar este código al contenido de su corazón si es necesario.
Nota: Al principio me decepcionó que ninguno de los
CollectionUtils
métodos proporciona una versión sobrecargada que le permite imponer la suyaComparator
(para que pueda redefinirlaequals
según sus propósitos).Pero de collections4 4.0 hay una nueva clase,
Equator
que "determina la igualdad entre los objetos de tipo T". Al examinar el código fuente de collections4 CollectionUtils.java, parecen estar usando esto con algunos métodos, pero por lo que puedo entender, esto no es aplicable a los métodos en la parte superior del archivo, usando laCardinalityHelper
clase ... que incluirdisjunction
yintersection
.Supongo que la gente de Apache todavía no se ha dado cuenta de esto porque no es trivial: tendrías que crear algo así como una clase "AbstractEquatingCollection", que en lugar de usar los elementos
equals
yhashCode
métodos inherentes a sus elementos, tendría que usar esos deEquator
todos los métodos básicos, comoadd
,contains
etc. NB, de hecho, cuando mira el código fuente,AbstractCollection
no implementaadd
, ni sus subclases abstractas comoAbstractSet
... tiene que esperar hasta las clases concretas comoHashSet
yArrayList
antesadd
está implementado. Todo un dolor de cabeza.Mientras tanto mira este espacio, supongo. La solución provisional obvia sería envolver todos sus elementos en una clase de envoltura a medida que utilice
equals
ehashCode
implementar el tipo de igualdad que desee ... luego manipularCollections
estos objetos de envoltura.fuente
Si la cardinalidad de los elementos no importa (es decir, los elementos repetidos se consideran uno), entonces hay una manera de hacerlo sin tener que ordenar:
boolean result = new HashSet<>(listA).equals(new HashSet<>(listB));
Esto creará un
Set
fuera de cada unoList
, y luego usaráHashSet
elequals
método que (por supuesto) ignora el pedido.Si la cardinalidad es importante, debe limitarse a las instalaciones proporcionadas por
List
; La respuesta de @ jschoen sería más adecuada en ese caso.fuente
La conversión de las listas a Multiset de Guava funciona muy bien. Se comparan independientemente de su orden y los elementos duplicados también se tienen en cuenta.
fuente
Esto se basa en la solución @cHao. Incluí varias correcciones y mejoras de rendimiento. Esto funciona aproximadamente el doble de rápido que la solución de copia ordenada igual. Funciona para cualquier tipo de colección. Las colecciones vacías y nulas se consideran iguales. Úselo para su ventaja;)
fuente
false
cuando una clave no existe o su recuento se vuelve negativo. Dado que el tamaño total de ambas listas coincide (esto se ha verificado por adelantado), es imposible tener valores distintos de cero después del segundo ciclo, ya que no puede haber valores positivos para una clave sin valores negativos para otra clave.Piense cómo lo haría usted mismo, sin una computadora o lenguaje de programación. Te doy dos listas de elementos, y tienes que decirme si contienen los mismos elementos. ¿Como lo harias?
Un enfoque, como se mencionó anteriormente, es ordenar las listas y luego ir elemento por elemento para ver si son iguales (que es lo que
List.equals
hace). Esto significa que puede modificar las listas o copiarlas, y sin conocer la asignación, no puedo saber si están permitidas o ambas.Otro enfoque sería revisar cada lista, contando cuántas veces aparece cada elemento. Si ambas listas tienen los mismos recuentos al final, tienen los mismos elementos. El código para eso sería traducir cada lista a un mapa
elem -> (# of times the elem appears in the list)
y luego llamarequals
a los dos mapas. Si los mapas sonHashMap
, cada una de esas traducciones es una operación O (N), como lo es la comparación. Eso le dará un algoritmo bastante eficiente en términos de tiempo, a costa de un poco de memoria adicional.fuente
Tuve este mismo problema y se me ocurrió una solución diferente. Este también funciona cuando hay duplicados involucrados:
Ventajas en comparación con algunas otras soluciones:
[1,2,3,3]
y otra matriz, la[1,2,2,3]
mayoría de las soluciones aquí le dicen que son las mismas cuando no considera el orden. Esta solución evita esto eliminando elementos iguales de las listas temporales;equals
) y no la igualdad de referencia (==
);implement Comparable
) para que esta solución funcione.fuente
Si no desea ordenar las colecciones y necesita el resultado de que ["A" "B" "C"] no es igual a ["B" "B" "A" "C"],
no es suficiente, también debe verificar el tamaño:
fuente
Solución que aprovecha el método de resta de CollectionUtils:
fuente
Si le importa el orden, simplemente use el método igual:
Si no te importa el orden, usa esto
fuente
Lo mejor de ambos mundos [@DiddiZ, @Chalkos]: este se basa principalmente en el método @Chalkos, pero corrige un error (ifst.next ()), mejora las comprobaciones iniciales (tomadas de @DiddiZ) y elimina la necesidad de copie la primera colección (solo elimina elementos de una copia de la segunda colección).
No requiere una función de hash o clasificación, y permite una pronta existencia de desigualdad, esta es la implementación más eficiente hasta ahora. Eso es a menos que tenga una longitud de colección de miles o más, y una función de hash muy simple.
fuente
Es una forma alternativa de verificar la igualdad de las listas de matrices que pueden contener valores nulos:
fuente
Mi solución para esto. No es tan genial, pero funciona bien.
fuente
En ese caso, las listas {"a", "b"} y {"b", "a"} son iguales. Y {"a", "b"} y {"b", "a", "c"} no son iguales. Si usa una lista de objetos complejos, recuerde anular el método igual , ya que contiene Todo lo usa en su interior.
fuente
AbstractCollection.containsAll()
. Debe permitir tener elementos duplicados de los que estamos hablandoLists
, no de los que estamos hablandoSets
. Por favor mira mi respuesta.