Comment maintenir une liste unique en Java?

104

Comment créer une liste d'objets uniques / distincts (pas de doublons) en Java?

En ce moment, j'utilise HashMap<String, Integer>pour le faire car la clé est écrasée et donc à la fin, nous pouvons obtenir HashMap.getKeySet()ce qui serait unique. Mais je suis sûr qu'il devrait y avoir une meilleure façon de le faire car la partie valeur est gaspillée ici.

Basil Bourque
la source

Réponses:

164

Vous pouvez utiliser un ensemble implémentation :

Quelques informations du JAVADoc:

Une collection qui ne contient aucun élément en double . Plus formellement, les ensembles ne contiennent aucune paire d'éléments e1 et e2 tels que e1.equals (e2), et au plus un élément nul. Comme son nom l'indique, cette interface modélise l'abstraction d'ensemble mathématique.

Remarque: il faut faire très attention si des objets mutables sont utilisés comme éléments d'ensemble. Le comportement d'un ensemble n'est pas spécifié si la valeur d'un objet est modifiée d'une manière qui affecte les comparaisons égales alors que l'objet est un élément de l'ensemble. Un cas particulier de cette interdiction est qu'il n'est pas permis pour un ensemble de se contenir comme un élément. »

Voici les implémentations:

  • HashSet

    Cette classe offre des performances à temps constant pour les opérations de base (ajouter, supprimer, contient et dimensionner), en supposant que la fonction de hachage répartit correctement les éléments entre les compartiments. Itérer sur cet ensemble nécessite un temps proportionnel à la somme de la taille de l'instance HashSet (le nombre d'éléments) plus la «capacité» de l'instance HashMap de sauvegarde (le nombre de compartiments). Ainsi, il est très important de ne pas définir la capacité initiale trop élevée (ou le facteur de charge trop bas) si les performances d'itération sont importantes.

    Lors de l'itération, HashSetl'ordre des éléments générés n'est pas défini.

  • LinkedHashSet

    Implémentation de table de hachage et de liste liée de l'interface Set, avec ordre d'itération prévisible. Cette implémentation diffère de HashSet en ce qu'elle maintient une liste à double lien parcourant toutes ses entrées. Cette liste chaînée définit l'ordre des itérations, 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. (Un élément e est réinséré dans un ensemble s si s.add (e) est invoqué alors que s.contains (e) renverrait true juste avant l'invocation.)

    Donc, la sortie du code ci-dessus ...

     Set<Integer> linkedHashSet = new LinkedHashSet<>();
     linkedHashSet.add(3);
     linkedHashSet.add(1);
     linkedHashSet.add(2);
    
     for (int i : linkedHashSet) {
         System.out.println(i);
     }

    ... sera nécessairement

    3
    1
    2
  • TreeSet

    Cette implémentation fournit un coût en temps log (n) garanti pour les opérations de base (ajouter, supprimer et contient). Par défaut, les éléments retournés lors de l'itération sont triés selon leur " ordre naturel ", donc le code ci-dessus ...

     Set<Integer> treeSet = new TreeSet<>();
     treeSet.add(3);
     treeSet.add(1);
     treeSet.add(2);
    
     for (int i : treeSet) {
         System.out.println(i);
     }

    ... affichera ceci:

    1
    2
    3

    (Vous pouvez également passer une Comparatorinstance à un TreeSetconstructeur, ce qui lui permet de trier les éléments dans un ordre différent.)

    Notez que l'ordre maintenu par un ensemble (qu'un comparateur explicite soit fourni ou non) doit être cohérent avec equals pour implémenter correctement l'interface Set. (Voir Comparable ou Comparator pour une définition précise de cohérent avec égal à égal.) Il en est ainsi parce que l'interface Set est définie en termes d'opération d'égalité, mais une instance TreeSet effectue toutes les comparaisons d'éléments en utilisant sa méthode compareTo (ou compare), donc deux les éléments jugés égaux par cette méthode sont, du point de vue de l'ensemble, égaux. Le comportement d'un ensemble est bien défini même si son ordre n'est pas cohérent avec les égaux; il ne parvient tout simplement pas à obéir au contrat général de l'interface Set.

Franc
la source
Maintenant je suis confus, lequel dois-je utiliser? J'ai juste besoin de maintenir une liste de chaînes uniques. Donc, fondamentalement, même lorsqu'une chaîne existante est ajoutée, elle devrait en fait être ajoutée.
1
Le choix vous appartient ... HashSet est universel et rapide, le jeu d'arbres est ordonné, LinkedHashset conserve l'ordre d'insertion ...
Frank
6
Ce n'est pas une LISTE ... donc, toutes les méthodes d'interface LIST ne sont pas disponibles.
marcolopes
2
Un ensemble n'est pas une liste, je ne peux pas rechercher des éléments par index dans un ensemble en temps O (1) (accès aléatoire).
wilmol
13

Je veux clarifier certaines choses ici pour l'affiche originale auxquelles d'autres ont fait allusion mais n'ont pas vraiment explicitement déclaré. Lorsque vous dites que vous voulez une liste unique, c'est la définition même d'un ensemble ordonné. Certaines autres différences clés entre l'interface Set et l'interface List sont que List vous permet de spécifier l'index d'insertion. Donc, la question est de savoir si vous avez vraiment besoin de l'interface de liste (c'est-à-dire pour la compatibilité avec une bibliothèque tierce, etc.), ou pouvez-vous repenser votre logiciel pour utiliser l'interface Set? Vous devez également considérer ce que vous faites avec l'interface. Est-il important de trouver des éléments par leur index? Combien d'éléments attendez-vous dans votre ensemble? Si vous avez de nombreux éléments, la commande est-elle importante?

Si vous avez vraiment besoin d'une liste qui a juste une contrainte unique, il existe la classe Apache Common Utils org.apache.commons.collections.list.SetUniqueList qui vous fournira l'interface List et la contrainte unique. Attention, cela casse l'interface de la liste. Vous obtiendrez cependant de meilleures performances si vous devez rechercher dans la liste par index. Si vous pouvez gérer l'interface Set et que vous avez un ensemble de données plus petit, LinkedHashSet pourrait être une bonne solution. Cela dépend simplement de la conception et de l'intention de votre logiciel.

Encore une fois, chaque collection présente certains avantages et inconvénients. Certaines insertions rapides mais des lectures lentes, certaines ont des lectures rapides mais des insertions lentes, etc. Il est logique de passer pas mal de temps avec la documentation des collections pour connaître les détails les plus fins de chaque classe et interface.

Paul Connolly
la source
3
Cela ne répond pas à la question. Pour critiquer ou demander des éclaircissements à un auteur, laissez un commentaire sous son message - vous pouvez toujours commenter vos propres messages, et une fois que vous avez une réputation suffisante, vous pourrez commenter n'importe quel article .
Zach Saucier
1
Il fournit une réponse, en fait. S'il veut juste une liste qui agit comme un Set, utilisez org.apache.commons.collections.list.SetUniqueList, mais en tant que programmeur, il / nous devrions être plus prudents que cela et réfléchir davantage au problème. Si cela améliore ma réponse, "Comment créer une liste unique en Java?" List uniqueList = new SetUniqueList () ;, c'est comme ça ....
Paul Connolly
3
Et Zach, je n'essaye pas d'être un imbécile, mais as-tu même lu ma réponse avant ton commentaire? Ou ne le comprenez-vous tout simplement pas? Si vous ne le comprenez pas, ce n'est pas grave - faites-le moi savoir et je développerai le sujet. Je ne pense pas que je devrais avoir à écrire un traité sur les structures de données pour donner une réponse amicale à la question de quelqu'un. Je ne me soucie pas non plus de trouver une manière douce de bâtir ma réputation de commentaire lorsque je connais la réponse et que personne d'autre ne l'a vraiment fournie.
Paul Connolly
1
Et au fait, je ne critiquais ni ne demandais des éclaircissements à l'auteur, je disais juste qu'il peut soit A) utiliser rapidement le cours que je lui ai donné, soit B) prendre le temps de vraiment comprendre les différences entre ces cours et de raconter à ses besoins. B prend évidemment plus de temps, mais se traduira par un meilleur code à long terme.
Paul Connolly
8

Utilisez new HashSet<String> un exemple:

import java.util.HashSet;
import java.util.Set;

public class MainClass {
  public static void main(String args[]) {
    String[] name1 = { "Amy", "Jose", "Jeremy", "Alice", "Patrick" };

    String[] name2 = { "Alan", "Amy", "Jeremy", "Helen", "Alexi" };

    String[] name3 = { "Adel", "Aaron", "Amy", "James", "Alice" };

    Set<String> letter = new HashSet<String>();

    for (int i = 0; i < name1.length; i++)
      letter.add(name1[i]);

    for (int j = 0; j < name2.length; j++)
      letter.add(name2[j]);

    for (int k = 0; k < name3.length; k++)
      letter.add(name3[k]);

    System.out.println(letter.size() + " letters must be sent to: " + letter);

  }
}
tim_a
la source
2
Juste en ajoutant le programme ci-dessus -> 11 lettres doivent être envoyées à: [Aaron, Alice, James, Adel, Jose, Jeremy, Amy, Alan, Patrick, Helen, Alexi]
Ammad
4

Vous pouvez simplement utiliser a HashSet<String>pour conserver une collection d'objets uniques. Si les Integervaleurs de votre carte sont importantes, vous pouvez utiliser à la place la containsKeyméthode des cartes pour tester si votre clé est déjà dans la carte.

Ted Hopp
la source
3

HashSet<String>(ou) toute Setimplémentation peut faire le travail pour vous. Setn'autorisez pas les doublons.

Voici javadoc pour HashSet.

kosa
la source
2

Je ne sais pas à quel point c'est efficace, mais cela a fonctionné pour moi dans un contexte simple.

List<int> uniqueNumbers = new ArrayList<>();

   public void AddNumberToList(int num)
    {
        if(!uniqueNumbers .contains(num)) {
            uniqueNumbers .add(num);
        }
    }
Zapnologica
la source
1

Vous pouvez utiliser l'une des classes d'implémentation d' java.util.Set<E>Interface, par exemple java.util.HashSet<String> la classe de collection.

Une collection qui ne contient aucun élément en double. Plus formellement, les ensembles ne contiennent aucune paire d'éléments e1 et e2 tels que e1.equals (e2), et au plus un élément nul. Comme son nom l'indique, cette interface modélise l'abstraction d'ensemble mathématique.

Yogendra Singh
la source