Existe-t-il un ensemble préservant l'ordre d'insertion qui implémente également List?

85

J'essaie de trouver une implémentation de java.util.Listet java.util.Seten même temps en Java. Je veux que cette classe autorise uniquement les éléments uniques (as Set) et conserve leur ordre (like List). Existe-t-il dans JDK 6?

C'est important d'avoir List<T>#add(int, T)pour que je puisse m'insérer dans une position spécifique.

yegor256
la source
Voulez-vous dire conserver leur ordre d' insertion ou un ordre défini par un Comparator? Voulez-vous également la sémantique de l' Listinterface?

Réponses:

207

TreeSetest trié par ordre d'élément; LinkedHashSetconserve l'ordre d'insertion. J'espère que l'un de ceux-là est ce que vous recherchiez.

Vous avez spécifié que vous voulez pouvoir insérer à un emplacement arbitraire , je suppose que vous devrez écrire le vôtre - créez simplement une classe contenant un HashSet<T>et un ArrayList<T>; lors de l'ajout d'un élément, vérifiez s'il fait partie de l'ensemble avant de l'ajouter à la liste.

Alternativement, les offres commons-collections4 d'Apache ListOrderedSetet SetUniqueList, qui se comportent de la même manière et doivent répondre aux exigences données.

Jon Skeet
la source
12

Voulez-vous dire comme LinkedHashSet? Cela préserve l'ordre d'entrée, mais n'autorise pas les doublons.

IMHO, c'est une exigence inhabituelle mais vous pouvez écrire une liste sans doublons.

class SetList<T> extends ArrayList<T> {
    @Override
    public boolean add(T t) {
        return !super.contains(t) && super.add(t);
    }

    @Override
    public void add(int index, T element) {
        if (!super.contains(element)) super.add(index, element);
    }

    @Override
    public boolean addAll(Collection<? extends T> c) {
        boolean added = false;
        for (T t : c)
            added |= add(t);
        return added;
    }

    @Override
    public boolean addAll(int index, Collection<? extends T> c) {
        boolean added = false;
        for (T t : c)
            if (!super.contains(t)) {
                super.add(index++, t);
                added = true;
            }
        return added;
    }
}
Peter Lawrey
la source
Il List
n'implémente
2
stackoverflow.com/a/8185105/253468 semble mieux car il n'a pas de O(n)complexité d'insertion, il y a un compromis à considérer entre le double stockage et l' O(log(n))opération d'insertion.
TWiStErRob
8

Vous ne pouvez pas mettre en œuvre Listet Setà la fois sans violation du contrat. Voir, par exemple, le Set.hashCodecontrat:

Le code de hachage d'un ensemble est défini comme étant la somme des codes de hachage des éléments de l'ensemble, où le code de hachage d'un élément nul est défini comme étant zéro.

En revanche voici le contrat de List.hashCode:

Le code de hachage d'une liste est défini comme étant le résultat du calcul suivant:

int hashCode = 1;
for (E e : list)
    hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());

Il est donc impossible d'implémenter une classe unique qui garantit que les deux contrats seront remplis. Le même problème pour la equalsmise en œuvre.

Tagir Valeev
la source
4

Si vous ne vous limitez pas au JDK 6, vous pouvez utiliser la bibliothèque de collections commune Apache qui offre une correspondance exacte pour vos besoins - ListOrderedSet . C'est comme Listet Setcombiné ensemble :)

Ondrej Bozek
la source
moins l' Listinterface
LateralFractal
0

J'ai eu un problème similaire, alors j'ai écrit le mien. Regardez ici . L' IndexedArraySetextension ArrayListet les implémentations Set, il doit donc prendre en charge toutes les opérations dont vous avez besoin. Notez que l'insertion d'éléments dans des emplacements au milieu d'un ArrayListpeut être lente pour les grandes listes car tous les éléments suivants doivent être déplacés. Mon IndexedArraySetne change pas ça.

JanKanis
la source
0

Une autre option (moins l' Listexigence d'interface) est celle de Guava ImmutableSet, qui préserve l'ordre d'insertion. Depuis leur page wiki :

À l'exception des collections triées, l' ordre est conservé à partir du moment de la construction. Par exemple,

ImmutableSet.of("a", "b", "c", "a", "d", "b")

itérera sur ses éléments dans l'ordre "a", "b", "c", "d".

kuporifique
la source