Recherche des différences entre deux listes en Java

1. Vue d'ensemble

La recherche de différences entre des collections d'objets du même type de données est une tâche de programmation courante. À titre d'exemple, imaginons que nous ayons une liste d'étudiants qui ont postulé pour un examen et une autre liste d'étudiants qui l'ont réussi. La différence entre ces deux listes nous donnerait les étudiants qui n'ont pas réussi l'examen.

En Java , il n'y a pas de moyen explicite de trouver les différences entre deux listes dans l' API List , bien que certaines méthodes d'assistance se rapprochent.

Dans ce tutoriel rapide, nous verrons comment trouver les différences entre les deux listes . Nous allons essayer quelques approches différentes, y compris Java brut (avec et sans Streams ) et en utilisant des bibliothèques tierces telles que Guava et les collections Apache Commons .

2. Configuration du test

Commençons par définir deux listes, que nous utiliserons pour tester nos exemples:

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. Utilisation de l' API Java List

Nous pouvons créer une copie d'une liste puis supprimer tous les éléments communs à l'autre , en utilisant la méthode List removeAll () :

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

Inversons cela pour trouver les différences dans l'autre sens:

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

Il faut également noter que si l'on veut retrouver les éléments communs entre les deux listes, List contient également une méthode retentionAll .

4. Utilisation de l'API Streams

Un flux Java peut être utilisé pour effectuer des opérations séquentielles sur les données des collections, ce qui inclut le filtrage des différences entre les listes :

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

Comme dans notre premier exemple, nous pouvons changer l'ordre des listes pour trouver les différents éléments de la deuxième liste:

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

Il faut noter que l'appel répété de List . contains () peut être une opération coûteuse pour des listes plus volumineuses.

5. Utilisation de bibliothèques tierces

5.1. Utilisation de Google Guava

Guava contient un ensemble pratique . méthode de différence , mais pour l'utiliser, nous devons d'abord convertir notre liste en un ensemble :

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

Il faut noter que la conversion de la liste en un ensemble aura pour effet de la dédupliquer et de la réorganiser.

5.2. Utilisation des collections Apache Commons

La classe CollectionUtils d' Apache Commons Collections contient une méthode removeAll .

Cette méthode fait la même chose que List . removeAll , tout en créant également une nouvelle collection pour le résultat :

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

6. Gestion des valeurs en double

Voyons maintenant trouver des différences lorsque deux listes contiennent des valeurs dupliquées.

Pour ce faire, nous devons supprimer les éléments en double de la première liste, précisément autant de fois qu'ils sont contenus dans la deuxième liste.

Dans notre exemple, la valeur «Jack» apparaît deux fois dans la première liste et une seule fois dans la deuxième liste:

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

Nous pouvons également y parvenir en utilisant la méthode de soustraction des collections Apache Commons :

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

7. Conclusion

Dans cet article, nous avons exploré plusieurs façons de trouver des différences entre les listes .

Dans les exemples, nous avons couvert une solution Java de base , une solution utilisant l' API Streams et des bibliothèques tierces telles que Google Guava et Apache Commons Collections.

Nous avons également vu comment gérer les valeurs en double.

Comme toujours, le code source complet est disponible à l'adresse over sur GitHub.