140 votes

Identifier les doublons dans une liste

J'ai une liste de type Integer, par exemple :

[1, 1, 2, 3, 3, 3]

Je voudrais une méthode pour retourner tous les doublons, par exemple :

[1, 3]

Quelle est la meilleure façon de procéder ?

2 votes

La liste d'entrée est-elle garantie d'être triée (comme dans votre exemple) ?

8 votes

Triez la liste, puis parcourez-la en conservant les valeurs actuelles et antérieures. si actuelle == antérieure, vous avez un doublon.

0 votes

Non, la liste n'est pas nécessairement triée.

201voto

leifg Points 2955

La méthode add de Set renvoie un booléen indiquant si une valeur existe déjà (true si elle n'existe pas, false si elle existe déjà, cf. Définir la documentation ).

Donc, il suffit d'itérer à travers toutes les valeurs :

public Set<Integer> findDuplicates(List<Integer> listContainingDuplicates)
{ 
  final Set<Integer> setToReturn = new HashSet<>(); 
  final Set<Integer> set1 = new HashSet<>();

  for (Integer yourInt : listContainingDuplicates)
  {
   if (!set1.add(yourInt))
   {
    setToReturn.add(yourInt);
   }
  }
  return setToReturn;
}

1 votes

Pourquoi avez-vous setToReturn ? Ne pouvez-vous pas simplement utiliser set1.add(votreInt) et retourner set1 ?

0 votes

Non, vous ne pouvez pas, car l'ensemble 1 contient toutes les valeurs (y compris celles qui ne sont pas en double).

0 votes

La documentation indique que add() "ajoute l'élément spécifié à cet ensemble s'il n'est pas déjà présent", ce qui donne l'impression que lorsque add renvoie false, rien n'a été ajouté.

61voto

John Strickler Points 8534

J'avais également besoin d'une solution à ce problème. J'ai utilisé la solution de Leifg et l'ai rendue générique.

private <T> Set<T> findDuplicates(Collection<T> collection) {

    Set<T> duplicates = new LinkedHashSet<>();
    Set<T> uniques = new HashSet<>();

    for(T t : collection) {
        if(!uniques.add(t)) {
            duplicates.add(t);
        }
    }

    return duplicates;
}

1 votes

Je sais que c'est 3 ans plus tard, mais pourquoi un LinkedHashedSet, c'est-à-dire pourquoi se soucier de l'ordre ?

4 votes

@AhmadRagab vous avez raison, LinkedHashSet n'est pas nécessaire, sauf si vous vous souciez de l'ordre dans lequel les doublons ont été trouvés (ce que je pense avoir fait à l'époque).

0 votes

Merci pour le suivi !

14voto

Ashkan Aryan Points 1695
int[] nums =  new int[] {1, 1, 2, 3, 3, 3};
Arrays.sort(nums);
for (int i = 0; i < nums.length-1; i++) {

    if (nums[i] == nums[i+1]) {
        System.out.println("duplicate item "+nums[i+1]+" at Location"+(i+1) );
    }

}

Évidemment, vous pouvez en faire ce que vous voulez (par exemple, les placer dans un Set pour obtenir une liste unique de valeurs en double) au lieu de les imprimer... Cela présente également l'avantage d'enregistrer l'emplacement des éléments en double.

6voto

Eng.Fouad Points 44085

Vous pouvez utiliser quelque chose comme ça :

List<Integer> newList = new ArrayList<Integer>();
for(int i : yourOldList)
{
    yourOldList.remove(i);
    if(yourOldList.contains(i) && !newList.contains(i)) newList.add(i);
}

2 votes

Utiliser List ici est très inefficace

2 votes

Et ne me lancez pas sur l'utilisation int comme type de variable ici. Cela signifie que pour chaque itération, un Integer est déboîté une fois et un int est boxé quatre fois !

1 votes

Je pense que vous pouvez facilement obtenir une ConcurrentModificationException lorsque vous essayez de supprimer un élément de la liste tout en l'itérant.

4voto

John B Points 17042

Utilisez un MultiMap pour stocker chaque valeur comme un ensemble clé/valeur. Ensuite, faites une itération parmi les clés et trouvez celles qui ont plusieurs valeurs.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X