121 votes

Comment maintenir une liste unique en Java ?

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

Pour l'instant, j'utilise HashMap<String, Integer> pour faire cela 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 un meilleur moyen de le faire car la partie valeur est gaspillée ici.

194voto

Frank Points 5808

Vous pouvez utiliser un Définir mise en œuvre :

Quelques informations provenant de la JAVADoc :

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

Nota: Il faut faire très attention si des objets mutables sont utilisés comme éléments d'un 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 d'égalités 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 comme élément.

Ce sont les mises en œuvre :

  • HashSet

    Cette classe offre des performances en temps constant 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 buckets. L'itération sur cet ensemble requiert un temps proportionnel à la somme de la taille de l'instance HashSet (le nombre d'éléments) et de la "capacité" de l'instance HashMap (le nombre de godets). Il est donc très important de ne pas fixer la capacité initiale trop élevée (ou le facteur de charge trop faible) si les performances d'itération sont importantes.

    Lors de l'itération d'un 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 liée à travers toutes ses entrées. Cette liste lié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. (Un élément e est réinséré dans un ensemble s si s.add(e) est invoqué alors que s.contains(e) renverrait vrai 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
  • Ensemble d'arbres

    Cette implémentation fournit un coût garanti en temps log(n) pour les opérations de base (ajouter, enlever et contenir). Par défaut, les éléments retournés par 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);
     }

    ...donnera ce résultat :

    1
    2
    3

    (Vous pouvez également passer un Comparator à une instance TreeSet pour qu'il trie 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 si l'on veut qu'il implémente correctement l'interface Set. (Voir Comparable ou Comparateur pour une définition précise de consistent with equals). En effet, l'interface Set est définie en termes d'opération equals, mais une instance TreeSet effectue toutes les comparaisons d'éléments à l'aide de sa méthode compareTo (ou compare), de sorte que deux é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 ordonnancement est incompatible avec l'opération equals ; il n'obéit simplement pas au contrat général de l'interface Set.

16voto

Paul Connolly Points 169

Je tiens à clarifier certaines choses pour l'affiche originale, auxquelles d'autres ont fait allusion mais qui n'ont pas vraiment été explicitées. Lorsque vous dites que vous voulez une liste unique, c'est la définition même d'un ensemble ordonné. D'autres différences importantes entre l'interface Set et l'interface List sont que List vous permet de spécifier l'index d'insertion. La question est donc de savoir si vous avez vraiment besoin de l'interface List (par exemple, pour des raisons de compatibilité avec une bibliothèque tierce, etc.) ou si vous pouvez concevoir votre logiciel de manière à 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 pensez-vous avoir dans votre ensemble ? Si vous avez beaucoup d'éléments, est-il important de les ordonner ?

Si vous avez vraiment besoin d'une liste qui n'a qu'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 vous accommoder de l'interface Set et que vous disposez d'un ensemble de données plus petit, LinkedHashSet peut être une bonne solution. Tout dépend de la conception et de l'intention de votre logiciel.

Là encore, chaque collection présente des avantages et des inconvénients. Certaines ont des insertions rapides mais des lectures lentes, d'autres ont des lectures rapides mais des insertions lentes, etc. Il est judicieux de consacrer un certain temps à la documentation sur les collections afin d'apprendre les moindres détails de chaque classe et interface.

12voto

tim_a Points 880

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

  }
}

6voto

Zapnologica Points 1296

Je ne sais pas si cela 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);
        }
    }

4voto

Ted Hopp Points 122617

Vous pourriez simplement utiliser un HashSet<String> pour maintenir une collection d'objets uniques. Si le Integer dans votre carte sont importantes, vous pouvez alors utiliser la fonction containsKey des cartes pour vérifier si votre clé se trouve déjà dans la carte.

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