Gibt es ein Set zur Beibehaltung der Einfügungsreihenfolge, das auch List implementiert?

84

Ich versuche eine Implementierung von java.util.Listund java.util.Setgleichzeitig in Java zu finden. Ich möchte, dass diese Klasse nur eindeutige Elemente (as Set) zulässt und deren Reihenfolge (like List) beibehält . Existiert es in JDK 6?

Es ist wichtig zu haben, List<T>#add(int, T)damit ich in eine bestimmte Position einfügen kann.

yegor256
quelle
Meinen Sie damit, ihre Einfügereihenfolge oder eine durch a definierte Reihenfolge beizubehalten Comparator? Möchten Sie auch die Semantik der ListSchnittstelle?

Antworten:

207

TreeSetist nach Elementreihenfolge sortiert; LinkedHashSetbehält die Einfügereihenfolge bei. Hoffentlich war eines davon das, wonach Sie gesucht haben.

Sie haben angegeben, dass Sie an einer beliebigen Stelle einfügen möchten. Ich vermute, Sie müssen Ihre eigene schreiben. Erstellen Sie einfach eine Klasse mit a HashSet<T>und a ArrayList<T>. Überprüfen Sie beim Hinzufügen eines Elements, ob es im Set enthalten ist, bevor Sie es zur Liste hinzufügen.

Alternativ Apache commons-collections4 Angebote ListOrderedSetund SetUniqueList, die sich ähnlich verhalten und sollte die gegebenen Anforderungen erfüllen.

Jon Skeet
quelle
12

Meinst du wie LinkedHashSet? Dadurch bleibt die Reihenfolge der Eingabe erhalten, es werden jedoch keine Duplikate zugelassen.

IMHO, es ist eine ungewöhnliche Anforderung, aber Sie können eine Liste ohne Duplikate schreiben.

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
quelle
Es implementiert keine ListSchnittstelle, siehe meine Änderungen an der Frage
yegor256
2
stackoverflow.com/a/8185105/253468 sieht besser aus, da es keine Einfügekomplexität aufweist. Es O(n)gibt einen Kompromiss zwischen doppeltem Speicher und O(log(n))Einfügevorgang.
TWiStErRob
7

Sie können nicht implementieren Listund Setsofort ohne Vertragsverletzung. Siehe zum Beispiel den Set.hashCodeVertrag:

Der Hash-Code einer Menge ist definiert als die Summe der Hash-Codes der Elemente in der Menge, wobei der Hash-Code eines Null-Elements als Null definiert ist.

Auf der anderen Seite ist hier der Vertrag von List.hashCode:

Der Hash-Code einer Liste ist das Ergebnis der folgenden Berechnung:

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

Es ist daher unmöglich, eine einzelne Klasse zu implementieren, die die Erfüllung beider Verträge garantiert. Das gleiche Problem bei der equalsImplementierung.

Tagir Valeev
quelle
4

Wenn Sie sich nicht auf JDK 6 beschränken möchten, können Sie die allgemeine Apache-Sammlungsbibliothek verwenden, die genau Ihren Anforderungen entspricht - ListOrderedSet . Es ist wie Listund zusammen Setkombiniert :)

Ondrej Bozek
quelle
minus der ListSchnittstelle
LateralFractal
0

Ich hatte ein ähnliches Problem, also schrieb ich mein eigenes. Siehe hier . Das IndexedArraySeterweitert ArrayListund implementiert Set, sollte also alle Operationen unterstützen, die Sie benötigen. Beachten Sie, dass das Einfügen von Elementen in Positionen in der Mitte von ArrayListfür große Listen langsam sein kann, da alle folgenden Elemente verschoben werden müssen. Das IndexedArraySetändert ich nicht.

JanKanis
quelle
0

Eine weitere Option (abzüglich der ListSchnittstellenanforderungen) ist die von Guava ImmutableSet, bei der die Einfügereihenfolge beibehalten wird. Von ihrer Wiki-Seite :

Mit Ausnahme der sortierten Sammlungen bleibt die Reihenfolge ab der Bauzeit erhalten. Beispielsweise,

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

iteriert über seine Elemente in der Reihenfolge "a", "b", "c", "d".

kuporific
quelle