web-dev-qa-db-fra.com

Existe-t-il une implémentation de liste sans doublon?

Je sais à propos de SortedSet , mais dans mon cas, j'ai besoin de quelque chose qui implémente List, et non pas Set. Alors, y a-t-il une implémentation disponible, dans l'API ou ailleurs?

Cela ne devrait pas être difficile à mettre en œuvre moi-même, mais je me suis dit pourquoi ne pas demander d'abord aux gens ici?

81
Yuval

Il n'y a pas de collection Java dans la bibliothèque standard pour ce faire. LinkedHashSet<E> conserve l'ordre similaire à un List, donc si vous enveloppez votre ensemble dans un List lorsque vous souhaitez l'utiliser comme List, vous Obtenez la sémantique que vous voulez.

Alternativement, le Commons Collections (ou commons-collections4, pour la version générique) a un List qui fait ce que vous voulez déjà: SetUniqueList / SetUniqueList<E> .

86
Calum

Voici ce que j'ai fait et ça marche.

En supposant que j'ai un ArrayList pour travailler avec la première chose que j'ai faite a été créée un nouveau LinkedHashMap.

LinkedHashSet<E> hashSet = new LinkedHashSet<E>()

Ensuite, j'essaie d'ajouter mon nouvel élément au LinkedHashSet. La méthode add ne modifie pas le LinkedHasSet et renvoie false si le nouvel élément est un doublon. Donc, cela devient une condition que je peux tester avant d’ajouter à la ArrayList.

if (hashSet.add(E)) arrayList.add(E);

C'est un moyen simple et élégant d'éviter que des doublons ne soient ajoutés à une liste de tableaux. Si vous le souhaitez, vous pouvez l'encapsuler et remplacer la méthode add dans une classe qui étend le ArrayList. Rappelez-vous simplement de traiter addAll en parcourant les éléments et en appelant la méthode add.

12
user3570018

Alors voici ce que j'ai finalement fait. J'espère que ça aidera quelqu'un d'autre.

class NoDuplicatesList<E> extends LinkedList<E> {
    @Override
    public boolean add(E e) {
        if (this.contains(e)) {
            return false;
        }
        else {
            return super.add(e);
        }
    }

    @Override
    public boolean addAll(Collection<? extends E> collection) {
        Collection<E> copy = new LinkedList<E>(collection);
        copy.removeAll(this);
        return super.addAll(copy);
    }

    @Override
    public boolean addAll(int index, Collection<? extends E> collection) {
        Collection<E> copy = new LinkedList<E>(collection);
        copy.removeAll(this);
        return super.addAll(index, copy);
    }

    @Override
    public void add(int index, E element) {
        if (this.contains(element)) {
            return;
        }
        else {
            super.add(index, element);
        }
    }
}   
10
Yuval

Vous devriez sérieusement considérer la réponse de Dhiller:

  1. Au lieu de vous inquiéter d'ajouter vos objets à une liste sans doublon, ajoutez-les à un ensemble (toute implémentation), qui filtrera par nature les doublons.
  2. Lorsque vous devez appeler la méthode nécessitant une liste, placez-la dans un new ArrayList(set) (ou dans un new LinkedList(set), peu importe).

Je pense que la solution que vous avez publiée avec NoDuplicatesList présente quelques problèmes, principalement avec la méthode contains(). De plus, votre classe ne gère pas la recherche de doublons dans la collection transmise à votre fonction addAll() méthode.

4
matt b

Pourquoi ne pas encapsuler un ensemble avec une liste, trier comme suit:

new ArrayList( new LinkedHashSet() )

Cela laisse l’autre implémentation à quelqu'un qui est un vrai maître des collections ;-)

4
Daniel Hiller

J'avais besoin de quelque chose comme ça, alors je suis allé dans les collections communes et j'utilisais SetUniqueList, mais quand j'ai lancé un test de performance, j'ai constaté qu'il ne semblait pas être optimisé par rapport à la casse si je souhaitais utiliser un ensemble et obtenir un tableau à l'aide du. Set.toArray (), le SetUniqueTest a mis 20: 1 à remplir, puis parcourir 100 000 chaînes en comparant avec l’implémentation implémentée, ce qui représente une différence considérable. Par conséquent, si vous vous inquiétez des performances, je vous recommande d’utiliser obtenez un tableau au lieu d'utiliser SetUniqueList, sauf si vous avez vraiment besoin de la logique de SetUniqueList, alors vous devez vérifier d'autres solutions ...

La méthode principale du code de test:

public static void main (String [] args) {

SetUniqueList pq = SetUniqueList.decorate(new ArrayList());
Set s = new TreeSet();

long t1 = 0L;
long t2 = 0L;
String t;


t1 = System.nanoTime();
for (int i = 0; i < 200000; i++) {
    pq.add("a" + Math.random());
}
while (!pq.isEmpty()) {
    t = (String) pq.remove(0);
}
t1 = System.nanoTime() - t1;

t2 = System.nanoTime();
for (int i = 0; i < 200000; i++) {
    s.add("a" + Math.random());
}

s.clear();
String[] d = (String[]) s.toArray(new String[0]);
s.clear();
for (int i = 0; i < d.length; i++) {
    t = d[i];

}
t2 = System.nanoTime() - t2;

System.out.println((double)t1/1000/1000/1000); //seconds
System.out.println((double)t2/1000/1000/1000); //seconds
System.out.println(((double) t1) / t2);        //comparing results

}

Cordialement Mohammed Sleem http://abusleem.net/blog

3
Mohammed Sleem

NOTE: cela ne prend pas subList implémentation en compte.

import Java.util.ArrayList;
import Java.util.Collection;
import Java.util.HashSet;
import Java.util.Set;

public class UniqueList<T> extends ArrayList<T> {

    private static final long serialVersionUID = 1L;

    /** Unique elements SET */
    private final Set<T> set=new HashSet();

    /** Used by addAll methods */
    private Collection<T> addUnique(Collection<? extends T> col) {
        Collection<T> unique=new ArrayList();
        for(T e: col){
            if (set.add(e)) unique.add(e);
        }
        return unique;
    }

    @Override
    public boolean add(T e) {
        return set.add(e) ? super.add(e) : false;
    }

    @Override
    public boolean addAll(Collection<? extends T> col) {
        return super.addAll(addUnique(col));
    }

    @Override
    public void add(int index, T e) {
        if (set.add(e)) super.add(index, e);
    }

    @Override
    public boolean addAll(int index, Collection<? extends T> col) {
        return super.addAll(index, addUnique(col));
    }

}
1
marcolopes

Le documentation pour les interfaces de collection dit:

Set - une collection qui ne peut pas contenir d'éléments en double.
Liste - une collection ordonnée (parfois appelée séquence). Les listes peuvent contenir des éléments en double.

Donc, si vous ne voulez pas de doublons, vous ne devriez probablement pas utiliser une liste.

0
Hauch