573 votes

Comment puis-je supprimer les éléments répétés d'ArrayList?

J'ai une ArrayList et je veux supprimer les chaînes répétées. Comment puis-je faire cela?

1093voto

jonathan-stafford Points 2785

Si vous ne voulez pas de doublons dans une Collection, vous devriez vous demander pourquoi vous utilisez une Collection qui permet les doublons. La manière la plus simple de supprimer les éléments répétés est d'ajouter le contenu à un Set (qui ne permettra pas les doublons) puis d'ajouter à nouveau le Set à l'ArrayList:

Set set = new HashSet<>(votreListe);
votreListe.clear();
votreListe.addAll(set);

Bien sûr, cela détruit l'ordre des éléments dans l'ArrayList.

290 votes

Voir aussi LinkedHashSet, si vous souhaitez conserver l'ordre.

0 votes

Mais cela créera juste l'ensemble sans doublons, je veux savoir quel numéro était en double en O(n) temps

0 votes

Chetan, trouver les éléments en O(n) est possible si l'ensemble des valeurs possibles est petit (pensez à Byte ou Short); un BitSet ou similaire peut ensuite être utilisé pour stocker et rechercher les valeurs déjà rencontrées en O(1) temps. Mais encore une fois - avec un si petit ensemble de valeurs, le faire en O(n log n) pourrait de toute façon ne pas poser de problème puisque n est faible. (Ce commentaire ne s'applique pas à l'auteur original, qui doit le faire avec String.)

317voto

abahgat Points 6479

Bien que la conversion de l'ArrayList en un HashSet supprime efficacement les doublons, si vous avez besoin de préserver l'ordre d'insertion, je vous suggère plutôt d'utiliser cette variante

// list est une Liste de Strings
Set s = new LinkedHashSet<>(list);

Ensuite, si vous avez besoin de récupérer une référence de type List, vous pouvez à nouveau utiliser le constructeur de conversion.

12 votes

LinkedHashSet fait-il des garanties quant à la conservation de plusieurs doublons de la liste ? Par exemple, si les positions 1, 3 et 5 sont des doublons dans la liste d'origine, peut-on supposer que ce processus supprimera 3 et 5 ? Ou peut-être supprimer 1 et 3 ? Merci.

18 votes

@Matt: oui, cela le garantit. Les docs disent : "Cette liste chaînée définit l'ordre d'itération, qui est l'ordre dans lequel les éléments ont été insérés dans l'ensemble (ordre d'insertion). Notez que l'ordre d'insertion n'est pas affecté si un élément est réinséré dans l'ensemble."

0 votes

Très intéressant. J'ai une situation différente ici. Je n'essaie pas de trier une chaîne de caractères mais un autre objet appelé AwardYearSource. Cette classe a un attribut int appelé année. Je veux donc supprimer les doublons en fonction de l'année. c'est-à-dire, s'il y a l'année 2010 mentionnée plus d'une fois, je veux supprimer cet objet AwardYearSource. Comment puis-je faire cela ?

174voto

Vitalii Fedorenko Points 17469

En Java 8 :

List deduped = list.stream().distinct().collect(Collectors.toList());

Veuillez noter que le contrat hashCode-equals pour les membres de la liste doivent être respectés pour que le filtrage fonctionne correctement.

1 votes

Comment puis-je faire cela pour être insensible à la casse distinct ?

0 votes

@StackFlowed Si vous n'avez pas besoin de conserver l'ordre de la liste, vous pouvez utiliser addAll pour new TreeSet(String.CASE_INSENSITIVE_ORDER). Le premier élément ajouté restera dans l'ensemble. Ainsi, si votre liste contient "Chien" et "chien" (dans cet ordre), le TreeSet contiendra "Chien". Si l'ordre doit être préservé, alors avant la ligne dans la réponse, ajoutez list.replaceAll(String::toUpperCase);.

1 votes

Je reçois cette erreur : types incompatibles : List ne peut être converti en List

53voto

Bno Points 5688

Si vous ne voulez pas de doublons, utilisez un Set au lieu d'une List. Pour convertir une List en un Set, vous pouvez utiliser le code suivant :

// list est une List de Strings
Set s = new HashSet(list);

Si vraiment nécessaire, vous pouvez utiliser la même construction pour convertir un Set en List.

0 votes

De même, en bas du fil de discussion, j'ai donné une réponse où j'utilise Set pour l'objet personnalisé. Dans le cas où quelqu'un a un objet personnalisé comme "Contact" ou "Étudiant", il peut utiliser cette réponse qui fonctionne bien pour moi.

0 votes

Le problème survient lorsque vous devez spécifiquement accéder à un élément. Par exemple, lors de la liaison d'un objet à une vue d'élément de liste dans Android, vous obtenez son index. Ainsi, Set ne peut pas être utilisé ici.

0 votes

Comment puis-je aborder cela lorsque la liste est une liste d'objets

30voto

stbn Points 151

Voici une façon qui n'affecte pas l'ordre de votre liste:

ArrayList l1 = new ArrayList();
ArrayList l2 = new ArrayList();

Iterator iterator = l1.iterator();

while (iterator.hasNext()) {
    YourClass o = (YourClass) iterator.next();
    if(!l2.contains(o)) l2.add(o);
}

l1 est la liste originale et l2 est la liste sans éléments répétés (Assurez-vous que YourClass a la méthode equals selon ce que vous voulez représenter par égalité)

1 votes

Cette réponse manque de deux choses : 1) Il n'utilise pas les génériques, mais des types bruts (ArrayList devrait être utilisé à la place de ArrayList) 2) La création explicite de l'itérateur peut être évitée en utilisant un for (T current : l1) { ... }. Même si vous vouliez utiliser un Iterator explicitement, iterador est mal orthographié.

9 votes

Et cette implémentation fonctionne en temps quadratique, par rapport à l'implémentation de l'ensemble de hachage lié qui s'exécute en temps linéaire. (c'est-à-dire que cela prend 10 fois plus de temps sur une liste avec 10 éléments, 10 000 fois plus de temps sur une liste avec 10 000 éléments. Implémentation JDK 6 pour ArrayList.contains, l'implémentation JDK8 est la même.)

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