Ich habe verschiedene Möglichkeiten gesehen, ein Wörterbuch in C # zu durchlaufen. Gibt es einen Standardweg?
c#
dictionary
loops
Jake Stewart
quelle
quelle
Antworten:
quelle
var entry
In diesem Fall ist die Verwendung besser, und daher habe ich diese Antwort auf einen zweiten Blick anstatt auf den obigen abgestimmt.var
wenn Sie den Typ nicht kennen, ist im Allgemeinen eine schlechte Praxis.var
funktioniert dies nur, wenn der Typ zur Kompilierungszeit bekannt ist. Wenn Visual Studio den Typ kennt, können Sie ihn ebenfalls herausfinden.Wenn Sie versuchen, ein generisches Wörterbuch in C # wie ein assoziatives Array in einer anderen Sprache zu verwenden:
Oder verwenden Sie, wenn Sie nur die Schlüsselsammlung durchlaufen müssen
Und zum Schluss, wenn Sie nur an den Werten interessiert sind:
(Beachten Sie, dass das
var
Schlüsselwort eine optionale Funktion ab C # 3.0 ist. Sie können hier auch den genauen Typ Ihrer Schlüssel / Werte verwenden.)quelle
myDictionary
(es sei denn, dies ist natürlich der tatsächliche Name). Ich denke, die Verwendung von var ist gut, wenn der Typ offensichtlich ist, z. B.var x = "some string"
aber wenn es nicht sofort offensichtlich ist, denke ich, dass es fauler Code ist, der den Codeleser /var
sollte meiner Meinung nach sparsam eingesetzt werden. Insbesondere hier ist es nicht konstruktiv: Der TypKeyValuePair
ist wahrscheinlich für die Frage relevant.var
hat einen einzigartigen Zweck und ich glaube nicht, dass es "syntaktischer" Zucker ist. Ein gezielter Einsatz ist ein angemessener Ansatz.In einigen Fällen benötigen Sie möglicherweise einen Zähler, der durch die For-Loop-Implementierung bereitgestellt wird. Dafür bietet LINQ
ElementAt
Folgendes:quelle
ElementAt
O (n) -Operation?.ElementAt
in diesem Zusammenhang zu subtilen Fehlern führen. Weitaus ernster ist Arturos Punkt oben. Sie iterieren die Wörterbuchzeitendictionary.Count + 1
, die zu einer Komplexität von O (n ^ 2) für eine Operation führen, die nur O (n) sein sollte. Wenn Sie wirklich einen Index benötigen (wenn Sie dies tun, verwenden Sie wahrscheinlich zuerst den falschen Sammlungstyp), sollten Siedictionary.Select( (kvp, idx) => new {Index = idx, kvp.Key, kvp.Value})
stattdessen iterieren und nicht.ElementAt
innerhalb der Schleife verwenden.Kommt darauf an, ob du hinter den Schlüsseln oder den Werten her bist ...
Aus der
Dictionary(TKey, TValue)
Beschreibung der MSDN- Klasse:quelle
Im Allgemeinen ist die Frage nach dem "besten Weg" ohne einen bestimmten Kontext wie die Frage nach der besten Farbe .
Einerseits gibt es viele Farben und es gibt keine beste Farbe. Es kommt auf die Bedürfnisse und oft auch auf den Geschmack an.
Auf der anderen Seite gibt es viele Möglichkeiten, ein Wörterbuch in C # zu durchlaufen, und es gibt keinen besten Weg. Es kommt auf die Bedürfnisse und oft auch auf den Geschmack an.
Einfachster Weg
Wenn Sie nur den Wert benötigen (erlaubt es, ihn aufzurufen
item
, besser lesbar alskvp.Value
).Wenn Sie eine bestimmte Sortierreihenfolge benötigen
Im Allgemeinen sind Anfänger über die Reihenfolge der Aufzählung eines Wörterbuchs überrascht.
LINQ bietet eine präzise Syntax, mit der Sie die Reihenfolge (und viele andere Dinge) festlegen können, z.
Auch hier benötigen Sie möglicherweise nur den Wert. LINQ bietet auch eine präzise Lösung für:
item
, besser lesbar alskvp.Value
)Hier ist es:
Es gibt viel mehr reale Anwendungsfälle, die Sie anhand dieser Beispiele ausführen können. Wenn Sie keine bestimmte Bestellung benötigen, halten Sie sich einfach an den "einfachsten Weg" (siehe oben)!
quelle
.Values
keine Auswahlklausel sein.Value
Feld. Der genaue Typ, den ich hier sehe, istIOrderedEnumerable<KeyValuePair<TKey, TValue>>
. Vielleicht hast du etwas anderes gemeint? Können Sie eine vollständige Zeile schreiben, die zeigt, was Sie meinen (und sie testen)?items.Value
wie Sie vorgeschlagen haben. Im Fall des vierten Abschnitts, den Sie kommentiert haben,Select()
ist dies eine Möglichkeit,foreach
anstelle von Schlüssel-Wert-Paaren eine direkte Aufzählung der Werte im Wörterbuch zu veranlassen. Wenn Ihnen dasSelect()
in diesem Fall irgendwie nicht gefällt , bevorzugen Sie möglicherweise den dritten Codeabschnitt. Der vierte Abschnitt soll zeigen, dass die Sammlung mit LINQ vorverarbeitet werden kann..Keys.Orderby()
Sie eine Liste von Schlüsseln durchlaufen. Wenn das alles ist, was Sie brauchen, gut. Wenn Sie Werte benötigen, müssen Sie in der Schleife das Wörterbuch für jeden Schlüssel abfragen, um den Wert zu erhalten. In vielen Szenarien macht es keinen praktischen Unterschied. In einem Hochleistungsszenario wird dies der Fall sein. Wie ich am Anfang der Antwort schrieb: "Es gibt viele Wege (...) und es gibt keinen besten Weg. Es hängt von der Notwendigkeit und oft auch vom Geschmack ab."Ich würde sagen, foreach ist der Standardweg, obwohl es offensichtlich davon abhängt, wonach Sie suchen
Ist es das, wonach du suchst?
quelle
kvp
wird häufig verwendet, um KeyValuePair-Instanzen zu benennen, wenn über Wörterbücher und verwandte Datenstrukturen iteriert wird :foreach(var kvp in myDictionary){...
.Sie können dies auch in großen Wörterbüchern für die Multithread-Verarbeitung ausprobieren.
quelle
In C # 7.0 wurden Dekonstruktoren eingeführt. Wenn Sie eine .NET Core 2.0+ -Anwendung verwenden, enthält die Struktur
KeyValuePair<>
bereits eineDeconstruct()
für Sie. So können Sie tun:quelle
foreach (var (key, value) in dic.Select(x => (x.Key, x.Value)))
Ich schätze, dass diese Frage bereits viele Antworten erhalten hat, aber ich wollte ein wenig Nachforschungen anstellen.
Das Iterieren über ein Wörterbuch kann im Vergleich zum Iterieren über ein Array ziemlich langsam sein. In meinen Tests dauerte eine Iteration über ein Array 0,015003 Sekunden, während eine Iteration über ein Wörterbuch (mit der gleichen Anzahl von Elementen) 0,0365073 Sekunden dauerte, was 2,4-mal so lang ist! Obwohl ich viel größere Unterschiede gesehen habe. Zum Vergleich lag eine Liste irgendwo zwischen 0,00215043 Sekunden.
Das ist jedoch wie ein Vergleich von Äpfeln und Orangen. Mein Punkt ist, dass das Durchlaufen von Wörterbüchern langsam ist.
Wörterbücher sind für Suchvorgänge optimiert. Aus diesem Grund habe ich zwei Methoden erstellt. Einer macht einfach einen foreach, der andere iteriert die Schlüssel und schaut dann nach oben.
Dieser lädt die Schlüssel und iteriert stattdessen darüber (ich habe auch versucht, die Schlüssel in eine Zeichenfolge [] zu ziehen, aber der Unterschied war vernachlässigbar.
In diesem Beispiel dauerte der normale foreach-Test 0,0310062 und die Schlüsselversion 0,2205441. Das Laden aller Schlüssel und das Durchlaufen aller Suchvorgänge ist eindeutig viel langsamer!
Für einen abschließenden Test habe ich meine Iteration zehn Mal durchgeführt, um festzustellen, ob die Verwendung der Schlüssel hier Vorteile bringt (zu diesem Zeitpunkt war ich nur neugierig):
Hier ist die RunTest-Methode, mit der Sie visualisieren können, was gerade passiert.
Hier dauerte der normale foreach-Lauf 0,2820564 Sekunden (ungefähr zehnmal länger als eine einzelne Iteration - wie zu erwarten). Die Iteration über die Schlüssel dauerte 2,2249449 Sekunden.
Zum Hinzufügen bearbeitet: Beim Lesen einiger anderer Antworten fragte ich mich, was passieren würde, wenn ich Dictionary anstelle von Dictionary verwenden würde. In diesem Beispiel dauerte das Array 0,0120024 Sekunden, die Liste 0,0185037 Sekunden und das Wörterbuch 0,0465093 Sekunden. Es ist zu erwarten, dass der Datentyp einen Unterschied darin macht, wie viel langsamer das Wörterbuch ist.
Was sind meine Schlussfolgerungen ?
quelle
Es gibt viele Möglichkeiten. Mein persönlicher Favorit ist von KeyValuePair
Sie können auch die Schlüssel- und Wertesammlungen verwenden
quelle
Mit
.NET Framework 4.7
kann man Zersetzung verwendenSystem.ValueTuple NuGet package
Fügen Sie irgendwo hinzu und schreiben Sie, damit dieser Code in niedrigeren C # -Versionen funktioniertquelle
ValueTuple
integriert. Es ist als Nuget-Paket für frühere Versionen verfügbar. Noch wichtiger ist, dass C # 7.0+ benötigt wird, damit dieDeconstruct
Methode als Dekonstruktor für funktioniertvar (fruit, number) in fruits
.Ab C # 7 können Sie Objekte in Variablen zerlegen. Ich glaube, dies ist der beste Weg, um ein Wörterbuch zu durchlaufen.
Beispiel:
Erstellen Sie eine Erweiterungsmethode
KeyValuePair<TKey, TVal>
, die es dekonstruiert:Iterieren Sie über eine
Dictionary<TKey, TVal>
der folgenden Methodenquelle
Sie haben unten vorgeschlagen, zu iterieren
Zu Ihrer Information,
foreach
funktioniert nicht, wenn der Wert vom Typ Objekt ist.quelle
foreach
nicht, wenn welcher Wert vom Typ istobject
? Ansonsten macht das nicht viel Sinn.Einfachste Form zum Iterieren eines Wörterbuchs:
quelle
Fügen Sie mit C # 7 diese Erweiterungsmethode zu jedem Projekt Ihrer Lösung hinzu:
Und verwenden Sie diese einfache Syntax
Oder dieses, wenn Sie es vorziehen
Anstelle des Traditionellen
Die Erweiterungsmethode verwandelt die
KeyValuePair
von IhnenIDictionary<TKey, TValue>
in eine stark typisierte Methodetuple
, sodass Sie diese neue komfortable Syntax verwenden können.Es konvertiert -just- die erforderlichen Wörterbucheinträge in
tuples
, konvertiert also NICHT das gesamte Wörterbuch intuples
, sodass diesbezüglich keine Leistungsprobleme bestehen.Es gibt nur geringe Kosten für das Aufrufen der Erweiterungsmethode zum Erstellen eines
tuple
im Vergleich zurKeyValuePair
direkten Verwendung, was KEIN Problem sein sollte, wenn Sie dieKeyValuePair
Eigenschaften des 'Key
undValue
ohnehin neuen Schleifenvariablen zuweisen .In der Praxis eignet sich diese neue Syntax in den meisten Fällen sehr gut, mit Ausnahme von Szenarien mit extrem hoher Leistung auf niedriger Ebene, in denen Sie immer noch die Möglichkeit haben, sie einfach nicht an dieser bestimmten Stelle zu verwenden.
Schauen Sie sich das an: MSDN Blog - Neue Funktionen in C # 7
quelle
kvp.Key
undkvp.Value
für die Verwendung von Schlüssel bzw. Wert verwendet werden. Mit Tupeln erhalten Sie die Flexibilität, den Schlüssel und den Wert nach Ihren Wünschen zu benennen, ohne weitere Variablendeklarationen innerhalb des foreach-Blocks zu verwenden. Sie können beispielsweise Ihren Schlüssel alsfactoryName
und den Wert als benennenmodels
, was besonders nützlich ist, wenn Sie verschachtelte Schleifen (Wörterbücher von Wörterbüchern) erhalten: Die Codepflege wird viel einfacher. Probieren Sie es einfach aus! ;-)Ich weiß, dass dies eine sehr alte Frage ist, aber ich habe einige Erweiterungsmethoden erstellt, die nützlich sein könnten:
Auf diese Weise kann ich Code wie folgt schreiben:
quelle
Wenn Sie nur die Werte aufzählen müssen, verwenden Sie manchmal die Wertsammlung des Wörterbuchs:
Dieser Beitrag berichtet, dass dies die schnellste Methode ist: http://alexpinsker.blogspot.hk/2010/02/c-fastest-way-to-iterate-over.html
quelle
Ich habe diese Methode in der Dokumentation für die DictionaryBase-Klasse auf MSDN gefunden:
Dies war die einzige, die in einer Klasse, die von der DictionaryBase geerbt wurde, ordnungsgemäß funktionieren konnte.
quelle
Hashtable
foreach
ist am schnellsten und wenn Sie nur iterieren___.Values
, ist es auch schnellerquelle
ContainsKey()
diefor
Version an? Dies erhöht den Overhead, der in dem Code, mit dem Sie vergleichen, nicht vorhanden ist.TryGetValue()
existiert, um das genaue Muster "Wenn Schlüssel existiert, Element mit Schlüssel abrufen" zu ersetzen. Wenn Siedict
einen zusammenhängenden Bereich von Ganzzahlen von0
bis enthaltendictCount - 1
, wissen Sie, dass der Indexer nicht fehlschlagen kann. Andernfallsdict.Keys
sollten Sie iterieren. So oder so, neinContainsKey()
/TryGetValue()
nötig. Zuletzt veröffentlichen Sie bitte keine Screenshots des Codes.Ich werde den Vorteil von .NET 4.0+ nutzen und eine aktualisierte Antwort auf die ursprünglich akzeptierte geben:
quelle
Die Standardmethode zum Durchlaufen eines Wörterbuchs laut offizieller Dokumentation zu MSDN lautet:
quelle
Ich habe eine Erweiterung geschrieben, um ein Wörterbuch zu durchlaufen.
Dann können Sie anrufen
quelle
ForEach
Methode definiert , mit der Sieforeach (...) { }
... Scheint unnötig.Wenn Sie beispielsweise standardmäßig über die Wertsammlung iterieren möchten, können Sie IEnumerable <> implementieren, wobei T der Typ des Werteobjekts im Wörterbuch ist und "this" ein Wörterbuch ist.
quelle
Ich wollte nur meine 2 Cent hinzufügen, da sich die meisten Antworten auf foreach-loop beziehen. Bitte schauen Sie sich den folgenden Code an:
Obwohl dies einen zusätzlichen Aufruf von '.ToList ()' hinzufügt, kann es zu einer leichten Leistungsverbesserung kommen (wie hier für jeden im Vergleich zu someList.Foreach () {} ausgeführt ), insbesondere wenn Sie mit großen Wörterbüchern arbeiten und parallel laufen Option / hat überhaupt keine Wirkung.
Beachten Sie außerdem, dass Sie der Eigenschaft 'Value' in einer foreach-Schleife keine Werte zuweisen können. Auf der anderen Seite können Sie auch den 'Schlüssel' manipulieren, wodurch Sie möglicherweise zur Laufzeit in Schwierigkeiten geraten.
Wenn Sie nur Schlüssel und Werte "lesen" möchten, können Sie auch IEnumerable.Select () verwenden.
quelle
foreach
Sichtbarkeit von Nebeneffekten, wo sie hingehört .quelle
AggregateObject
dazu beiKeyValuePair
? Wo ist die "Iteration", wie in der Frage gefordert?foreach
, aber ich habe es oft benutzt. Hat meine Antwort wirklich eine Ablehnung verdient?Select
verwendet Iteration, um das Ergebnis zu bewirken, ist jedoch selbst kein Iterator. Die Arten von Dingen, für die iteration (foreach
) verwendet wird - insbesondere Operationen mit Nebenwirkungen - liegen außerhalb des Anwendungsbereichs von Linq, einschließlichSelect
. Das Lambda läuft erst, wennaggregateObjectCollection
es tatsächlich aufgezählt ist. Wenn diese Antwort als "erster Weg" genommen wird (dh vor einer Geraden verwendet wirdforeach
), werden schlechte Praktiken gefördert. In bestimmten Situationen gibt es möglicherweise Linq-Operationen, die vor dem Iterieren eines Wörterbuchs hilfreich sind , die jedoch die gestellte Frage nicht beantworten.Wörterbuch <TKey, TValue> Es handelt sich um eine generische Auflistungsklasse in c #, in der die Daten im Schlüsselwertformat gespeichert werden. Der Schlüssel muss eindeutig sein und darf nicht null sein, während der Wert doppelt und null sein kann. Wie jedes Element im Wörterbuch wird als KeyValuePair <TKey, TValue> -Struktur behandelt, die einen Schlüssel und seinen Wert darstellt. Daher sollten wir während der Iteration des Elements den Elementtyp KeyValuePair <TKey, TValue> verwenden. Unten ist das Beispiel.
quelle
Wenn Sie die for-Schleife verwenden möchten, können Sie dies tun:
quelle
foreach
Schleife und schlechtere Leistung, danew List<string>(dictionary.Keys)
diedictionary.Count
Zeiten wiederholt werden, bevor Sie überhaupt die Möglichkeit haben, ihn selbst zu wiederholen. Abgesehen davon, dass es subjektiv ist, nach dem "besten Weg" zu fragen, sehe ich nicht, wie sich dies als "bester Weg" oder "Standardweg" qualifizieren würde, den die Frage sucht. Zu "Wenn Sie für Schleife verwenden möchten ..." würde ich mit " Verwenden Sie keinefor
Schleife" kontern .foreach (var pair in dictionary.ToArray()) { }
. Dennoch denke ich, dass es gut wäre, in der Antwort die spezifischen Szenarien, in denen man diesen Code verwenden möchte, und die Auswirkungen davon klar zu machen.Wie bereits in dieser Antwort erwähnt , wird
KeyValuePair<TKey, TValue>
eineDeconstruct
Methode implementiert , die mit .NET Core 2.0, .NET Standard 2.1 und .NET Framework 5.0 (Vorschau) beginnt.Auf diese Weise ist es möglich, ein Wörterbuch auf
KeyValuePair
agnostische Weise zu durchlaufen :quelle
einfach mit linq
quelle
ToList()
weil diesForEach()
nur für dieList<>
Klasse definiert ist , aber warum tun Sie das alles anstatt nurforeach (var pair in dict) { }
? Ich würde sagen, das ist noch einfacher und hat nicht die gleichen Auswirkungen auf Speicher und Leistung. Diese genaue Lösung wurde ohnehin schon vor 3,5 Jahren in dieser Antwort vorgeschlagen.Zusätzlich zu den am höchsten bewerteten Posts, in denen eine Diskussion zwischen der Verwendung besteht
oder
Am vollständigsten ist Folgendes, da Sie den Wörterbuchtyp anhand der Initialisierung sehen können. Kvp ist KeyValuePair
quelle