web-dev-qa-db-fra.com

Comment maintenir une liste unique en Java?

Comment créer une liste d'objets uniques/distincts (sans 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() qui serait unique. Mais je suis sûr qu'il devrait y avoir une meilleure façon de faire ceci car la partie de valeur est gaspillée ici.

88
user1804287

Vous pouvez utiliser une implémentation Set :

Quelques informations du JAVADoc:

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

Remarque: Il faut être extrêmement prudent si des objets mutables sont utilisés comme éléments de l'ensemble. Le comportement d'un ensemble n'est pas spécifié si la valeur d'un objet est modifiée de manière à affecter 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 à un ensemble de se contenir lui-même en tant qu’élément. "

Ce sont les implémentations:

  • HashSet

    Cette classe offre des performances constantes dans le temps pour les opérations de base (ajout, suppression, contenu et taille), en supposant que la fonction de hachage disperse 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). Par conséquent, il est très important de ne pas définir une capacité initiale trop élevée (ou un facteur de charge trop bas) si les performances d'itération sont importantes.

    Lors de l'itération d'une HashSet, l'ordre des éléments cédés est indéfini.

  • LinkedHashSet

    Implémentation de la table de hachage et de la liste chaînée de l'interface Set avec un ordre d'itération prévisible. Cette implémentation diffère de HashSet en ce qu'elle maintient une liste doublement chaînée traversant toutes ses entrées. Cette liste liée définit l'ordre des itérations, c'est-à-dire 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 le jeu. (Un élément e est réinséré dans un ensemble s si s.add (e) est invoqué alors que s.contains (e) renvoie true immédiatement 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 de log (n) garanti pour les opérations de base (ajout, suppression et contenu). Par défaut, les éléments retournés à l'itération sont triés par 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);
     }
    

    ... produira ceci:

    1
    2
    3
    

    (Vous pouvez également passer une instance de Comparator à un constructeur TreeSet, 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 égal si vous voulez implémenter correctement l'interface Set. (Voir Comparable ou Comparator pour une définition précise de cohérent avec égal à.) En effet, l'interface Set est définie en fonction de l'opération equals, mais une instance TreeSet effectue toutes les comparaisons d'éléments à l'aide de sa méthode compareTo (ou comparaison). les éléments réputé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 est incohérent avec égaux; il ne parvient tout simplement pas à respecter le contrat général de l'interface Set.

141
Frank

Je veux clarifier certaines choses ici pour l'affiche originale auxquelles d'autres ont fait allusion mais qui n'ont pas été explicitement énoncées. Lorsque vous dites que vous voulez une liste unique, c'est la définition même d'un ensemble ordonné. La liste permet d’indiquer l’index d’insertion. La question est donc 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 redéfinir votre logiciel pour utiliser l'interface Set? Vous devez également tenir compte de 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 set? Si vous avez plusieurs éléments, commander est-il important?

Si vous avez réellement besoin d'une liste comportant simplement une contrainte unique, il existe la classe org.Apache.commons.collections.list.SetUniqueList de Apache Common Utils qui vous fournira l'interface List et la contrainte unique. Remarquez que cela casse l'interface de la liste. Cependant, vous obtiendrez de meilleures performances si vous devez chercher dans la liste par index. Si vous pouvez gérer l'interface Set et que vous avez un ensemble de données plus petit, alors LinkedHashSet peut être un bon moyen. Cela dépend 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 les lectures lentes, d'autres avec des lectures rapides, mais les insertions lentes, etc.

10
Paul Connolly

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);

  }
}
9
tim_a

Vous pouvez simplement utiliser un HashSet<String> pour gérer une collection d'objets uniques. Si les valeurs Integer de votre carte sont importantes, vous pouvez alors utiliser la méthode des cartes containsKey pour vérifier si votre clé est déjà dans la carte.

3
Ted Hopp

HashSet<String> (ou) toute implémentation de Set peut faire le travail à votre place. Set n'autorise pas les doublons.

Voici javadoc pour HashSet.

2
kosa

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);
        }
    }
2
Zapnologica

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

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

1
Yogendra Singh