Ich habe diese Frage gelesen , warum dies nicht möglich ist, aber keine Lösung für das Problem gefunden.
Ich möchte ein Element aus einem .NET abrufen HashSet<T>
. Ich suche nach einer Methode, die diese Signatur haben würde:
/// <summary>
/// Determines if this set contains an item equal to <paramref name="item"/>,
/// according to the comparison mechanism that was used when the set was created.
/// The set is not changed. If the set does contain an item equal to
/// <paramref name="item"/>, then the item from the set is returned.
/// </summary>
bool TryGetItem<T>(T item, out T foundItem);
Das Durchsuchen des Satzes nach einem Gegenstand mit einer solchen Methode wäre O (1). Die einzige Möglichkeit, ein Element von a abzurufen, HashSet<T>
besteht darin, alle Elemente aufzulisten, die O (n) sind.
Ich habe keine andere Problemumgehung für dieses Problem gefunden, als meine eigene zu erstellen HashSet<T>
oder eine zu verwenden Dictionary<K, V>
. Irgendeine andere Idee?
Hinweis:
Ich möchte nicht überprüfen, ob HashSet<T>
der Artikel enthalten ist. Ich möchte den Verweis auf das Element erhalten, das in der gespeichert ist, HashSet<T>
da ich es aktualisieren muss (ohne es durch eine andere Instanz zu ersetzen). Das Element, an das ich übergeben würde, TryGetItem
wäre gleich (gemäß dem Vergleichsmechanismus, den ich an den Konstruktor übergeben habe), aber es wäre nicht dieselbe Referenz.
Antworten:
Was Sie verlangen, wurde vor einem Jahr zu .NET Core und kürzlich zu .NET 4.7.2 hinzugefügt :
Die Signatur lautet wie folgt (in .NET 4.7.2 und höher):
PS .: Falls Sie interessiert sind, gibt es verwandte Funktionen, die sie in Zukunft hinzufügen - HashSet.GetOrAdd (T).
quelle
Dies ist tatsächlich eine große Lücke in der Sammlung. Sie benötigen entweder nur ein Schlüsselwörterbuch oder ein HashSet, mit dem Objektreferenzen abgerufen werden können. So viele Leute haben danach gefragt, warum es nicht repariert wird, ist mir ein Rätsel.
Ohne Bibliotheken von Drittanbietern besteht die beste Problemumgehung darin,
Dictionary<T, T>
Schlüssel zu verwenden, die mit Werten identisch sind, da Dictionary seine Einträge als Hash-Tabelle speichert. In Bezug auf die Leistung ist es dasselbe wie das HashSet, aber es verschwendet natürlich Speicher (Größe eines Zeigers pro Eintrag).quelle
Diese Methode wurde zu .NET Framework 4.7.2 (und zuvor zu .NET Core 2.0 ) hinzugefügt . siehe
HashSet<T>.TryGetValue
. Zitieren der Quelle :quelle
Was ist mit der Überladung des String-Gleichheitsvergleichs:
Und deklarieren Sie dann das HashSet als:
quelle
HashSet
, um den spezifischen Wertekonverter bereitzustellen. Eine optimale Lösung wäre,TryGetValue
eine neue Instanz des Spezialisten zu übergebenStringEqualityComparer
(andernfallsas StringEqualityComparer
könnte dies zu einer Null führen, wodurch der.val1
Zugriff auf die Eigenschaft ausgelöst wird). Auf diese Weise kann StringEqualityComparer zu einer verschachtelten privaten Klasse in HashSetExtension werden. Im Falle eines überschriebenen Gleichheitsvergleichs sollte der StringEqualityComparer die Standardeinstellung aufrufen.Ein weiterer Trick würde Reflection
InternalIndexOf
ausführen , indem auf die interne Funktion von HashSet zugegriffen wird. Beachten Sie, dass die Feldnamen fest codiert sind. Wenn sich diese in zukünftigen .NET-Versionen ändern, wird dies nicht funktionieren.Hinweis: Wenn Sie Mono verwenden, sollten Sie den Feldnamen von
m_slots
in ändern_slots
.Prüfung:
quelle
Ok, also kannst du es so machen
Dies dient zum Abrufen einer neuen Instanz des ausgewählten Objekts. Um Ihr Objekt zu aktualisieren, sollten Sie Folgendes verwenden:
quelle
Jetzt hat .NET Core 2.0 genau diese Methode.
HashSet.TryGetValue (T, T) -Methode
quelle
SortedSet hätte unter diesen Umständen wahrscheinlich eine Suchzeit von O (log n), wenn dies eine Option ist. Immer noch nicht O (1), aber zumindest besser.
quelle
Die Implementierung von @ mp666 answer wurde so geändert, dass sie für jede Art von HashSet verwendet werden kann und das Überschreiben des Standardgleichheitsvergleichs ermöglicht.
quelle
Enumerable.Contains
, werden alle Elemente des Satzes aufgelistet und verglichen, wodurch alle Vorteile verloren gehen, die die Hash-Implementierung des Satzes bietet. Dann können Sie auch einfach schreibenset.SingleOrDefault(e => set.Comparer.Equals(e, obj))
, das das gleiche Verhalten und die gleichen Leistungsmerkmale wie Ihre Lösung aufweist.HashSet verfügt über eine Contains (T) -Methode.
Sie können einen IEqualityComparer angeben, wenn Sie eine benutzerdefinierte Vergleichsmethode benötigen (z. B. ein Personenobjekt speichern, aber die SSN für den Gleichheitsvergleich verwenden).
quelle
Sie können auch die ToList () -Methode verwenden und einen Indexer darauf anwenden.
quelle