Aus dem Eintrag von MSDN in der Dictionary.TryGetValue-Methode :
Diese Methode kombiniert die Funktionalität der ContainsKey-Methode und der Item-Eigenschaft.
Wird der Schlüssel nicht gefunden, erhält der Wertparameter den entsprechenden Standardwert für den Werttyp TValue. Beispiel: 0 (Null) für Ganzzahltypen, Falsch für Boolesche Typen und Null für Referenztypen.
Verwenden Sie die TryGetValue-Methode, wenn Ihr Code häufig versucht, auf Schlüssel zuzugreifen, die nicht im Wörterbuch enthalten sind. Die Verwendung dieser Methode ist effizienter als das Abfangen der von der Item-Eigenschaft ausgelösten KeyNotFoundException.
Diese Methode nähert sich einer O (1) -Operation.
Aus der Beschreibung geht nicht hervor, ob es effizienter oder nur bequemer ist, als ContainsKey aufzurufen und dann die Suche durchzuführen. Tut die Implementierung vonTryGetValue
nur ContainsKey und dann Item auf oder ist sie tatsächlich effizienter, wenn nur eine einzige Suche durchgeführt wird?
Mit anderen Worten, was ist effizienter (dh welches führt weniger Suchvorgänge durch):
Dictionary<int,int> dict;
//...//
int ival;
if(dict.ContainsKey(ikey))
{
ival = dict[ikey];
}
else
{
ival = default(int);
}
oder
Dictionary<int,int> dict;
//...//
int ival;
dict.TryGetValue(ikey, out ival);
Hinweis: Ich suche keinen Benchmark!
quelle
if(dict.ContainsKey(ikey)) dict[ikey]++; else dict.Add(ikey, 0);
. Aber ich denke, dasTryGetValue
ist immer noch effizienter, da get und set der Indexer-Eigenschaft verwendet werden, nicht wahr?Ein schneller Benchmark zeigt, dass er
TryGetValue
eine leichte Kante hat:Dies erzeugt
Der
ContainsKey + Item
Zugriff wird um etwa 40% langsamer, wenn eine gleichmäßige Mischung aus Treffern und Fehlschlägen angenommen wird.Wenn ich das Programm so ändere, dass es immer fehlt (dh immer nach oben schaut
"b"
), werden die beiden Versionen außerdem gleich schnell:Wenn ich es aber "alle Treffer" mache,
TryGetValue
bleibt das ein klarer Gewinner:quelle
TryGetValue
sollten Sie weit voraus sein. Auch ... ein Nitpick ...DateTime
ist nicht der beste Weg, um Leistungsmessungen zu erfassen.TryGetValue
geht noch weiter in Führung. Ich habe die Antwort so bearbeitet, dass sie die Szenarien "Alle Treffer" und "Alle Fehler" enthält.Any
- So :Any(i=>i.Key==key)
. In diesem Fall ist das eine schlechte lineare Suche im Wörterbuch.DateTime.Now
wird nur auf wenige ms genau sein. Verwenden Sie stattdessen dieStopwatch
Klasse inSystem.Diagnostics
(die QueryPerformanceCounter unter dem Deckmantel verwendet, um eine viel höhere Genauigkeit zu erzielen). Es ist auch einfacher zu bedienen.Da bisher keine der Antworten die Frage tatsächlich beantwortet, ist hier eine akzeptable Antwort, die ich nach einigen Recherchen gefunden habe:
Wenn Sie TryGetValue dekompilieren, sehen Sie, dass es dies tut:
Die ContainsKey-Methode lautet:
TryGetValue ist also nur ContainsKey plus eine Array-Suche, wenn das Element vorhanden ist.
Quelle
Es scheint, dass TryGetValue fast doppelt so schnell ist wie die ContainsKey + Item-Kombination.
quelle
Wen interessiert das :-)
Sie fragen wahrscheinlich, weil
TryGetValue
es schmerzhaft ist, es zu verwenden - kapseln Sie es also so mit einer Erweiterungsmethode.Dann rufen Sie einfach an:
oder
quelle
this
aber es stellte sich heraus, dass ich meine Methode zweimal in meiner Codebasis dupliziert habe - einmal mit und eine ohnethis
, deshalb habe ich sie nie gefangen! danke fürs reparieren!TryGetValue
Weist dem Parameter out value einen Standardwert zu, wenn der Schlüssel nicht vorhanden ist. Dies könnte vereinfacht werden.if(!dic.TryGetValue(key, out value item)) item = dic[key] = new Item();
Warum testest du es nicht?
Aber ich bin mir ziemlich sicher, dass
TryGetValue
das schneller geht, weil es nur eine Suche macht. Dies ist natürlich nicht garantiert, dh unterschiedliche Implementierungen können unterschiedliche Leistungsmerkmale aufweisen.Ich würde ein Wörterbuch implementieren, indem ich eine interne
Find
Funktion erstelle , die den Steckplatz für ein Element findet, und dann den Rest darauf aufbaue.quelle
Alle bisherigen Antworten sind zwar gut, verfehlen jedoch einen wichtigen Punkt.
Methoden in die Klassen einer API (z. B. das .NET Framework) sind Teil einer Schnittstellendefinition (keine C # - oder VB-Schnittstelle, sondern eine Schnittstelle im Sinne der Informatik).
Daher ist es normalerweise falsch zu fragen, ob das Aufrufen einer solchen Methode schneller ist, es sei denn, Geschwindigkeit ist Teil der formalen Schnittstellendefinition (was in diesem Fall nicht der Fall ist).
Traditionell ist diese Art von Verknüpfung (Kombination von Suchen und Abrufen) effizienter, unabhängig von Sprache, Infrastruktur, Betriebssystem, Plattform oder Maschinenarchitektur. Es ist auch besser lesbar, da es Ihre Absicht explizit ausdrückt, anstatt sie zu implizieren (aus der Struktur Ihres Codes).
Die Antwort (von einem alten Hack mit Grizzles) lautet also definitiv "Ja" (TryGetValue ist einer Kombination aus ContainsKey und Item [Get] vorzuziehen, um einen Wert aus einem Wörterbuch abzurufen).
Wenn Sie der Meinung sind, dass dies seltsam klingt, stellen Sie sich Folgendes vor: Auch wenn aktuelle Implementierungen von TryGetValue, ContainsKey und Item [Get] keinen Geschwindigkeitsunterschied ergeben, können Sie davon ausgehen, dass eine zukünftige Implementierung (z. B. .NET v5) wahrscheinlich ist. wird tun (TryGetValue wird schneller sein). Denken Sie an die Lebensdauer Ihrer Software.
Abgesehen davon ist es interessant festzustellen, dass typische moderne Schnittstellendefinitionstechnologien immer noch selten ein Mittel zur formalen Definition von Zeitbeschränkungen bieten. Vielleicht .NET v5?
quelle
Wenn Sie ein schnelles Testprogramm erstellen, gibt es mit TryGetValue mit 1 Million Elementen in einem Wörterbuch definitiv eine Verbesserung.
Ergebnisse:
Enthält Schlüssel + Gegenstand für 1000000 Treffer: 45 ms
TryGetValue für 1000000 Treffer: 26 ms
Hier ist die Test-App:
quelle
Wenn auf meinem Computer mit viel RAM im RELEASE-Modus (nicht DEBUG) ausgeführt wird,
ContainsKey
entsprichtTryGetValue
/,try-catch
wenn alle Einträge inDictionary<>
gefunden wurden.ContainsKey
übertrifft sie alle bei weitem, wenn nur wenige Wörterbucheinträge nicht gefunden wurden (in meinem Beispiel untenMAXVAL
auf etwas Größeres eingestellt, alsENTRIES
dass einige Einträge übersehen werden):Ergebnisse:
Hier ist mein Code:
quelle
Neben dem Entwerfen eines Mikrobenchmarks, das in einer praktischen Umgebung genaue Ergebnisse liefert, können Sie auch die Referenzquelle von .NET Framework überprüfen.
System.Collections.Generic.Dictionary<TKey, TValue>.TryGetValue(TKey, out TValue)
System.Collections.Generic.Dictionary<TKey, TValue>.ContainsKey(TKey)
System.Collections.Generic.Dictionary<TKey, TValue>.Item(TKey)
Alle rufen die
FindEntry(TKey)
Methode auf, die den größten Teil der Arbeit erledigt und das Ergebnis nicht speichert, sodass der AufrufTryGetValue
fast doppelt so schnell ist wieContainsKey
+Item
.Die unbequeme Schnittstelle von
TryGetValue
kann unter Verwendung einer Erweiterungsmethode angepasst werden :Seit C # 7.1 können Sie durch
default(TValue)
plain ersetzendefault
. Der Typ wird abgeleitet.Verwendung:
Es wird
null
für Referenztypen zurückgegeben, deren Suche fehlschlägt, sofern kein expliziter Standardwert angegeben ist.quelle
Wenn Sie versuchen, den Wert aus dem Wörterbuch zu entfernen, ist TryGetValue (Schlüssel, Aus-Wert) die beste Option. Wenn Sie jedoch prüfen, ob der Schlüssel vorhanden ist, suchen Sie nach einer neuen Einfügung, ohne alte Schlüssel zu überschreiben. und nur mit diesem Umfang ist ContainsKey (Schlüssel) die beste Option, Benchmark kann dies bestätigen:
Dies ist ein echtes Beispiel. Ich habe einen Dienst, der für jeden erstellten "Artikel" eine progressive Nummer verknüpft. Diese Nummer muss jedes Mal, wenn Sie einen neuen Artikel erstellen, frei gefunden werden. Wenn Sie einen Artikel löschen, wird die kostenlose Nummer kostenlos, dies ist natürlich nicht optimiert, da ich eine statische Variable habe, die die aktuelle Nummer zwischenspeichert, aber falls Sie alle Nummern beenden, können Sie von 0 bis UInt32.MaxValue neu beginnen
Test ausgeführt:
Hinzufügen von Elementen zur Hashtabelle ...
Fertig in 0,5908 - Pause ....
Hinzufügen von Elementen zum Wörterbuch ...
Fertig in 0,2679 - Pause ....
Finden der ersten freien Nummer zum Einfügen
Erste Methode : Enthält den
Schlüssel Fertig in 0,0561 - Mehrwert 1000000 im Wörterbuch - Pause ....
Zweite Methode: TryGetValue
Fertig in 0,0643 - Mehrwert 1000001 im Wörterbuch - Pause ....
Test-Hashtabelle
Fertig in 0, 3015 - Mehrwert 1000000 in Hashtabelle - Pause ....
Drücken Sie eine beliebige Taste, um fortzufahren. .
Wenn einige von Ihnen fragen, ob die ContainsKeys einen Vorteil haben könnten, habe ich sogar versucht, den TryGetValue mit dem Contains-Schlüssel zu invertieren. Das Ergebnis ist das gleiche.
Für mich hängt abschließend alles davon ab, wie sich das Programm verhält.
quelle