C # Sammlung setzen?

488

Weiß jemand, ob es ein gutes Äquivalent zu Javas SetSammlung in C # gibt? Ich weiß, dass Sie eine Menge mit a Dictionaryoder a etwas nachahmen können HashTable, indem Sie die Werte auffüllen, aber ignorieren, aber das ist keine sehr elegante Methode.

Omar Kooheji
quelle

Antworten:

142

Versuchen Sie HashSet :

Die HashSet (Of T) -Klasse bietet leistungsstarke Set-Operationen. Ein Set ist eine Sammlung, die keine doppelten Elemente enthält und deren Elemente in keiner bestimmten Reihenfolge vorliegen ...

Die Kapazität eines HashSet (Of T) -Objekts ist die Anzahl der Elemente, die das Objekt enthalten kann. Die Kapazität eines HashSet (Of T) -Objekts erhöht sich automatisch, wenn dem Objekt Elemente hinzugefügt werden.

Die HashSet (Of T) -Klasse basiert auf dem Modell mathematischer Mengen und bietet leistungsstarke Mengenoperationen, die dem Zugriff auf die Schlüssel der Dictionary- (Of TKey, TValue) oder Hashtable- Sammlungen ähneln . In einfachen Worten kann die HashSet (Of T) -Klasse als eine Dictionary- Sammlung (Of TKey, TValue) ohne Werte betrachtet werden.

Eine HashSet (Of T) -Sammlung ist nicht sortiert und kann keine doppelten Elemente enthalten ...

Leahn Novash
quelle
8
Leider wurden HashSets erst kürzlich hinzugefügt. Wenn Sie in einer älteren Version des Frameworks arbeiten, müssen Sie sich an Ihr Munged Dictionary <> oder Ihre Hashtable halten.
Greg D
413

Wenn Sie .NET 3.5 verwenden, können Sie verwenden HashSet<T>. Es ist wahr, dass .NET nicht so gut für Sets geeignet ist wie Java.

Die Wintellect PowerCollections können ebenfalls hilfreich sein.

Jon Skeet
quelle
16
Ich vermute, dass Set in einigen Sprachen ein Schlüsselwort ist, das Probleme verursachen kann.
Jon Skeet
3
@ Manish: Nein, ist es nicht. Siehe Abschnitt 2.4.3 der C # 3-Spezifikation. Es hat nur eine besondere Bedeutung für Eigenschaften.
Jon Skeet
28
Der Grund für den Aufruf von HashSet anstelle von Set ist der gleiche wie in Java. "Set" beschreibt eine Schnittstelle, während "HashSet" eine Implementierung beschreibt. Dies ist ein Set, das von einer Hash-Map unterstützt wird. Auf diese Weise wissen wir (oder sollten stark erwarten), dass das Einfügen und der Zugriff O (1) -Zugriffszeit benötigen, im Gegensatz zu einem "LinkedListSet", was dazu führen würde, dass das Einfügen und der Zugriff O (n) -Zeit benötigen.
David Souther
5
Was meinst du mit ".NET ist nicht so gut für Sets geeignet wie Java."? Ist dieses Set im Vergleich zu Java irgendwie unvollkommen?
Louis Rhys
34
@ Louis: Über welches Set sprichst du? Java hat viele verschiedene Implementierungen von Set für verschiedene Situationen. .NET hatte eine in .NET 3.5 (HashSet) und zwei in .NET 4 (HashSet und SortedSet). Die Tatsache, dass wir zunächst auf .NET 3.5 warten mussten, ist ziemlich überraschend.
Jon Skeet
26

Wenn Sie .NET 4.0 oder höher verwenden:

In dem Fall, in dem Sie sortieren müssen, verwenden Sie SortedSet<T>. Wenn Sie dies nicht tun, verwenden Sie es, HashSet<T>da es O(1)zum Suchen und Bearbeiten von Vorgängen dient. Während SortedSet<T>ist O(log n)für die Suche und Operationen manipulieren.

Derek W.
quelle
13

Ich benutze einen Wrapper um a Dictionary<T, object>und speichere Nullen in den Werten. Dies gibt O (1) das Hinzufügen, Nachschlagen und Entfernen der Schlüssel und verhält sich in jeder Hinsicht wie ein Satz.

thecoop
quelle
2
Sie müssen meinen, dass es in etwa std :: unordered_set entspricht. std :: set ist bestellt. Sie können beispielsweise schnell den Start- und Endpunkt eines Bereichs finden und vom Anfang bis zum Ende iterieren, indem Sie Elemente in Schlüsselreihenfolge aufrufen. SortedDictionary ist etwa vergleichbar mit std :: set.
Doug65536
11

Schauen Sie sich PowerCollections bei CodePlex an. Neben Set und OrderedSet gibt es noch einige andere nützliche Sammlungstypen wie Deque, MultiDictionary, Bag, OrderedBag, OrderedDictionary und OrderedMultiDictionary.

Für weitere Sammlungen gibt es auch die C5 Generic Collection Library .

dpan
quelle
-5

Ich weiß, dass dies ein alter Thread ist, aber ich hatte das gleiche Problem und fand HashSet sehr unzuverlässig, da GetHashCode () bei gleichem Startwert unterschiedliche Codes zurückgegeben hat. Also dachte ich mir, warum nicht einfach eine Liste verwenden und die Add-Methode so ausblenden

public class UniqueList<T> : List<T>
{
    public new void Add(T obj)
    {
        if(!Contains(obj))
        {
            base.Add(obj);
        }
    }
}

Da List die Equals-Methode ausschließlich zur Bestimmung der Gleichheit verwendet, können Sie die Equals-Methode für Ihren T-Typ definieren, um sicherzustellen, dass Sie die gewünschten Ergebnisse erhalten.

Bob Heck
quelle
13
Der Grund, warum Sie dies nicht verwenden möchten, List.Containsliegt in der O(n)Komplexität, was bedeutet, dass Ihre AddMethode jetzt auch komplex wird O(n). Angenommen, die Größe der inneren Sammlung muss Addfür beide nicht geändert werden Listund HashMapsollte O(1)komplex sein. TLDR: Das wird funktionieren, aber es ist hackig und weniger effizient.
Richard Marskell - Drackir
6
Wenn Ihre Objekte keinen geeigneten Wert für GetHashCode zurückgeben, sollten Sie sie nicht in einen Hash-basierten Container einfügen. Es wäre besser, GetHashCode zu reparieren, als einen weniger effizienten Container zu verwenden.
Bmm6o