Encontrar las diferencias entre dos listas en Java

1. Información general

Encontrar diferencias entre colecciones de objetos del mismo tipo de datos es una tarea de programación común. Como ejemplo, imagine que tenemos una lista de estudiantes que solicitaron un examen y otra lista de estudiantes que lo aprobaron. La diferencia entre esas dos listas nos daría los estudiantes que no aprobaron el examen.

En Java , no hay manera explícita para encontrar diferencias entre dos listas en la lista de API, aunque hay algunos métodos de ayuda que se acercan.

En este tutorial rápido, veremos cómo encontrar las diferencias entre las dos listas . Intentaremos algunos enfoques diferentes, incluido Java simple (con y sin Streams ) y el uso de bibliotecas de terceros como Guava y Apache Commons Collections .

2. Configuración de prueba

Comencemos por definir dos listas, que usaremos para probar nuestros ejemplos:

public class FindDifferencesBetweenListsUnitTest { private static final List listOne = Arrays.asList("Jack", "Tom", "Sam", "John", "James", "Jack"); private static final List listTwo = Arrays.asList("Jack", "Daniel", "Sam", "Alan", "James", "George"); }

3. Uso de la API de lista de Java

Podemos crear una copia de una lista y luego eliminar todos los elementos comunes con la otra , usando el método List removeAll () :

List differences = new ArrayList(listOne); differences.removeAll(listTwo); assertEquals(2, differences.size()); assertThat(differences).containsExactly("Tom", "John");

Invirtamos esto para encontrar las diferencias al revés:

List differences = new ArrayList(listTwo); differences.removeAll(listOne); assertEquals(3, differences.size()); assertThat(differences).containsExactly("Daniel", "Alan", "George");

También debemos tener en cuenta que si queremos encontrar los elementos comunes entre las dos listas, List también contiene un método keepAll .

4. Uso de la API de Streams

Un Java corriente puede ser utilizado para realizar operaciones secuenciales en los datos en colecciones, que incluye el filtrado de las diferencias entre las listas :

List differences = listOne.stream() .filter(element -> !listTwo.contains(element)) .collect(Collectors.toList()); assertEquals(2, differences.size()); assertThat(differences).containsExactly("Tom", "John");

Como en nuestro primer ejemplo, podemos cambiar el orden de las listas para encontrar los diferentes elementos de la segunda lista:

List differences = listTwo.stream() .filter(element -> !listOne.contains(element)) .collect(Collectors.toList()); assertEquals(3, differences.size()); assertThat(differences).containsExactly("Daniel", "Alan", "George");

Debemos tener en cuenta que el llamado repetido de List . contiene () puede ser una operación costosa para listas más grandes.

5. Uso de bibliotecas de terceros

5.1. Usando Google Guava

Guayaba contiene unos prácticos sets . método de diferencia , pero para usarlo primero necesitamos convertir nuestra Lista en un Conjunto :

List differences = new ArrayList(Sets.difference(Sets.newHashSet(listOne), Sets.newHashSet(listTwo))); assertEquals(2, differences.size()); assertThat(differences).containsExactlyInAnyOrder("Tom", "John");

Debemos tener en cuenta que convertir la Lista en un Conjunto tendrá el efecto de deduplicarlo y reordenarlo.

5.2. Usar colecciones de Apache Commons

La clase CollectionUtils de Apache Commons Collections contiene un método removeAll .

Este método hace lo mismo que List . removeAll , al mismo tiempo que crea una nueva colección para el resultado :

List differences = new ArrayList((CollectionUtils.removeAll(listOne, listTwo))); assertEquals(2, differences.size()); assertThat(differences).containsExactly("Tom", "John");

6. Manejo de valores duplicados

Veamos ahora cómo encontrar diferencias cuando dos listas contienen valores duplicados.

Para lograr esto, necesitamos eliminar los elementos duplicados de la primera lista, precisamente tantas veces como estén contenidos en la segunda lista.

En nuestro ejemplo, el valor "Jack" aparece dos veces en la primera lista y solo una vez en la segunda lista:

List differences = new ArrayList(listOne); listTwo.forEach(differences::remove); assertThat(differences).containsExactly("Tom", "John", "Jack");

También podemos lograr esto usando el método de sustracción de Apache Commons Collections :

List differences = new ArrayList(CollectionUtils.subtract(listOne, listTwo)); assertEquals(3, differences.size()); assertThat(differences).containsExactly("Tom", "John", "Jack");

7. Conclusión

En este artículo, exploramos algunas formas de encontrar diferencias entre listas .

En los ejemplos, cubrimos una solución básica de Java , una solución que usa la API Streams y con bibliotecas de terceros como Google Guava y Apache Commons Collections.

También vimos cómo manejar valores duplicados.

Como siempre, el código fuente completo está disponible en GitHub.