Was ist der beste Weg, um ein Wörterbuch zu durchlaufen?


2626

Ich habe verschiedene Möglichkeiten gesehen, ein Wörterbuch in C # zu durchlaufen. Gibt es einen Standardweg?


108
Ich bin überrascht, dass es viele Antworten auf diese Frage gibt, zusammen mit einer, die 923 Mal positiv bewertet wurde. (Verwendet natürlich jeden). Ich würde argumentieren oder zumindest hinzufügen, dass Sie es wahrscheinlich sind, wenn Sie ein Wörterbuch durchlaufen müssen Ich musste diesen Kommentar abgeben, weil ich gesehen habe, wie Wörterbücher auf eine Weise missbraucht wurden, die meiner Meinung nach nicht angemessen war. Ja, es kann seltene Umstände geben, wenn Sie das Wörterbuch iterieren, anstatt nachzuschlagen Bitte beachten Sie dies, bevor Sie sich fragen, wie Sie ein Wörterbuch durchlaufen sollen.
Vikas Gupta

74
@VikasGupta Was würden Sie vorschlagen, um etwas mit einer Sammlung von Schlüssel-Wert-Paaren zu tun, wenn Sie nicht wissen, wie die Schlüssel aussehen werden?
Nasch

26
@displayName Wenn Sie mit jedem Schlüssel-Wert-Paar etwas tun möchten, aber keinen Verweis auf die Schlüssel haben, die zum Nachschlagen von Werten verwendet werden sollen, würden Sie das Wörterbuch durchlaufen, oder? Ich habe nur darauf hingewiesen, dass es Zeiten geben könnte, in denen Sie dies tun möchten, obwohl Vikas behauptet, dass dies normalerweise eine falsche Verwendung ist.
Nasch

34
Zu sagen, dass es sich um eine falsche Verwendung handelt, bedeutet, dass es eine bessere Alternative gibt. Was ist das für eine Alternative?
Kyle Delaney

40
VikasGupta ist falsch, ich kann das nach vielen Jahren leistungsstarker C # - und C ++ - Programmierung in nicht-theoretischen Szenarien bestätigen. Es gibt in der Tat häufige Fälle, in denen man ein Wörterbuch erstellt, eindeutige Schlüssel-Wert-Paare speichert und dann über diese Werte iteriert, die nachweislich eindeutige Schlüssel in der Sammlung enthalten. Das Erstellen weiterer Sammlungen ist eine wirklich ineffiziente und kostspielige Methode, um Wörterbuchiterationen zu vermeiden. Bitte geben Sie eine gute Alternative als Antwort auf die Frage an, die Ihren Standpunkt verdeutlicht, andernfalls ist Ihr Kommentar ziemlich unsinnig.
sɐunıɔ ןɐ qɐp

Antworten:


3713
foreach(KeyValuePair<string, string> entry in myDictionary)
{
    // do something with entry.Value or entry.Key
}

29
Was ist, wenn ich den Typ des Schlüssels / Werts im Wörterbuch nicht genau kenne? var entryIn diesem Fall ist die Verwendung besser, und daher habe ich diese Antwort auf einen zweiten Blick anstatt auf den obigen abgestimmt.
Ozair Kafray

93
Die Verwendung von @OzairKafray, varwenn Sie den Typ nicht kennen, ist im Allgemeinen eine schlechte Praxis.
Nate

52
Diese Antwort ist überlegen, da Pablo nicht standardmäßig die Verwendung des Lazy-Codierers "var" verwendet hat, die den Rückgabetyp verschleiert.
MonkeyWrench

119
@ MonkeyWrench: Meh. Visual Studio kennt den Typ. Alles, was Sie tun müssen, ist den Mauszeiger über die Variable zu halten, um dies herauszufinden.
Robert Harvey

31
Soweit ich weiß, varfunktioniert dies nur, wenn der Typ zur Kompilierungszeit bekannt ist. Wenn Visual Studio den Typ kennt, können Sie ihn ebenfalls herausfinden.
Kyle Delaney

866

Wenn Sie versuchen, ein generisches Wörterbuch in C # wie ein assoziatives Array in einer anderen Sprache zu verwenden:

foreach(var item in myDictionary)
{
  foo(item.Key);
  bar(item.Value);
}

Oder verwenden Sie, wenn Sie nur die Schlüsselsammlung durchlaufen müssen

foreach(var item in myDictionary.Keys)
{
  foo(item);
}

Und zum Schluss, wenn Sie nur an den Werten interessiert sind:

foreach(var item in myDictionary.Values)
{
  foo(item);
}

(Beachten Sie, dass das varSchlüsselwort eine optionale Funktion ab C # 3.0 ist. Sie können hier auch den genauen Typ Ihrer Schlüssel / Werte verwenden.)


11
Die Var-Funktion wird am meisten für Ihren ersten Codeblock benötigt :)
Nawfal

27
Ich schätze, dass diese Antwort darauf hinweist, dass Sie die Schlüssel oder Werte explizit durchlaufen können.
Rotsiser Mho

11
Ich mag die Verwendung von var hier nicht. Da es sich nur um syntaktischen Zucker handelt, warum sollte man ihn hier verwenden? Wenn jemand versucht, den Code zu lesen, muss er um den Code herum springen, um den Typ zu bestimmen 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 /
-prüfer

8
varsollte meiner Meinung nach sparsam eingesetzt werden. Insbesondere hier ist es nicht konstruktiv: Der Typ KeyValuePairist wahrscheinlich für die Frage relevant.
Sinjai

3
varhat einen einzigartigen Zweck und ich glaube nicht, dass es "syntaktischer" Zucker ist. Ein gezielter Einsatz ist ein angemessener Ansatz.
Joshua K

159

In einigen Fällen benötigen Sie möglicherweise einen Zähler, der durch die For-Loop-Implementierung bereitgestellt wird. Dafür bietet LINQ ElementAtFolgendes:

for (int index = 0; index < dictionary.Count; index++) {
  var item = dictionary.ElementAt(index);
  var itemKey = item.Key;
  var itemValue = item.Value;
}

21
Beachten Sie Folgendes, um die Methode '.ElementAt' zu verwenden: using System.Linq; Dies ist in fx nicht enthalten. automatisch generierte Testklassen.
Tinia

14
Dies ist der richtige Weg, wenn Sie die mit den Schlüsseln verknüpften Werte ändern. Andernfalls wird beim Ändern und Verwenden von foreach () eine Ausnahme ausgelöst.
Mike de Klerk

27
Ist das keine ElementAtO (n) -Operation?
Arturo Torres Sánchez

162
Diese Antwort verdient so viele positive Stimmen überhaupt nicht. Ein Wörterbuch hat keine implizite Reihenfolge, daher kann die Verwendung .ElementAtin diesem Zusammenhang zu subtilen Fehlern führen. Weitaus ernster ist Arturos Punkt oben. Sie iterieren die Wörterbuchzeiten dictionary.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 Sie dictionary.Select( (kvp, idx) => new {Index = idx, kvp.Key, kvp.Value})stattdessen iterieren und nicht .ElementAtinnerhalb der Schleife verwenden.
Spender

5
ElementAt - o (n) Operation! Ernsthaft? Dies ist das Beispiel, wie Sie es nicht tun sollten. Diese vielen positiven Stimmen?
Mukesh Adhvaryu

96

Kommt darauf an, ob du hinter den Schlüsseln oder den Werten her bist ...

Aus der Dictionary(TKey, TValue)Beschreibung der MSDN- Klasse:

// When you use foreach to enumerate dictionary elements,
// the elements are retrieved as KeyValuePair objects.
Console.WriteLine();
foreach( KeyValuePair<string, string> kvp in openWith )
{
    Console.WriteLine("Key = {0}, Value = {1}", 
        kvp.Key, kvp.Value);
}

// To get the values alone, use the Values property.
Dictionary<string, string>.ValueCollection valueColl =
    openWith.Values;

// The elements of the ValueCollection are strongly typed
// with the type that was specified for dictionary values.
Console.WriteLine();
foreach( string s in valueColl )
{
    Console.WriteLine("Value = {0}", s);
}

// To get the keys alone, use the Keys property.
Dictionary<string, string>.KeyCollection keyColl =
    openWith.Keys;

// The elements of the KeyCollection are strongly typed
// with the type that was specified for dictionary keys.
Console.WriteLine();
foreach( string s in keyColl )
{
    Console.WriteLine("Key = {0}", s);
}

82

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

foreach (var kvp in items)
{
    // key is kvp.Key
    doStuff(kvp.Value)
}

Wenn Sie nur den Wert benötigen (erlaubt es, ihn aufzurufen item, besser lesbar als kvp.Value).

foreach (var item in items.Values)
{
    doStuff(item)
}

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.

foreach (var kvp in items.OrderBy(kvp => kvp.Key))
{
    // key is kvp.Key
    doStuff(kvp.Value)
}

Auch hier benötigen Sie möglicherweise nur den Wert. LINQ bietet auch eine präzise Lösung für:

  • iterieren Sie direkt auf dem Wert (ermöglicht es, ihn aufzurufen item, besser lesbar als kvp.Value)
  • aber sortiert nach den Schlüsseln

Hier ist es:

foreach (var item in items.OrderBy(kvp => kvp.Key).Select(kvp => kvp.Value))
{
    doStuff(item)
}

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)!


Die letzte sollte .Valueskeine Auswahlklausel sein.
Mafii

@ Mafii Bist du sicher? Von OrderBy zurückgegebene Werte sind nicht vom Typ KeyValuePair, sie haben kein ValueFeld. Der genaue Typ, den ich hier sehe, ist IOrderedEnumerable<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)?
Stéphane Gourichon

Ich denke, diese Antwort enthält, was ich meine: stackoverflow.com/a/141105/5962841, aber korrigieren Sie mich, wenn ich etwas verwirrt habe
Mafii

1
@Mafii Lies meine ganze Antwort noch einmal durch, Erklärungen zwischen den Codeabschnitten geben Auskunft über den Kontext. Die Antwort, die Sie erwähnen, entspricht dem zweiten Codeabschnitt in meiner Antwort (keine Bestellung erforderlich). Dort habe ich gerade geschrieben, items.Valuewie Sie vorgeschlagen haben. Im Fall des vierten Abschnitts, den Sie kommentiert haben, Select()ist dies eine Möglichkeit, foreachanstelle von Schlüssel-Wert-Paaren eine direkte Aufzählung der Werte im Wörterbuch zu veranlassen. Wenn Ihnen das Select()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.
Stéphane Gourichon

1
Wenn Sie dies tun, werden .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."
Stéphane Gourichon

53

Ich würde sagen, foreach ist der Standardweg, obwohl es offensichtlich davon abhängt, wonach Sie suchen

foreach(var kvp in my_dictionary) {
  ...
}

Ist es das, wonach du suchst?


42
Ist es nicht verwirrend, den Artikel "Wert" zu nennen? Normalerweise verwenden Sie Syntax wie "value.Key" und "value.Value", was für alle anderen, die den Code lesen, nicht sehr intuitiv ist, insbesondere wenn sie nicht mit der Implementierung des .Net-Wörterbuchs vertraut sind .
RenniePet

3
@RenniePet kvpwird häufig verwendet, um KeyValuePair-Instanzen zu benennen, wenn über Wörterbücher und verwandte Datenstrukturen iteriert wird : foreach(var kvp in myDictionary){....
mbx

37

Sie können dies auch in großen Wörterbüchern für die Multithread-Verarbeitung ausprobieren.

dictionary
.AsParallel()
.ForAll(pair => 
{ 
    // Process pair.Key and pair.Value here
});

8
@ WiiMaxx und wichtiger, wenn diese Elemente NICHT voneinander abhängen
Mafii

36

In C # 7.0 wurden Dekonstruktoren eingeführt. Wenn Sie eine .NET Core 2.0+ -Anwendung verwenden, enthält die StrukturKeyValuePair<>bereits eineDeconstruct()für Sie. So können Sie tun:

var dic = new Dictionary<int, string>() { { 1, "One" }, { 2, "Two" }, { 3, "Three" } };
foreach (var (key, value) in dic) {
    Console.WriteLine($"Item [{key}] = {value}");
}
//Or
foreach (var (_, value) in dic) {
    Console.WriteLine($"Item [NO_ID] = {value}");
}
//Or
foreach ((int key, string value) in dic) {
    Console.WriteLine($"Item [{key}] = {value}");
}

Geben Sie hier die Bildbeschreibung ein


5
Wenn Sie .NET Framework verwenden, das mindestens bis 4.7.2 nicht über die Dekonstruktion auf dem KeyValuePair verfügt, versuchen Sie foreach (var (key, value) in dic.Select(x => (x.Key, x.Value)))
Folgendes

29

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.

public static string Normal(Dictionary<string, string> dictionary)
{
    string value;
    int count = 0;
    foreach (var kvp in dictionary)
    {
        value = kvp.Value;
        count++;
    }

    return "Normal";
}

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.

public static string Keys(Dictionary<string, string> dictionary)
{
    string value;
    int count = 0;
    foreach (var key in dictionary.Keys)
    {
        value = dictionary[key];
        count++;
    }

    return "Keys";
}

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.

private static string RunTest<T>(T dictionary, Func<T, string> function)
{            
    DateTime start = DateTime.Now;
    string name = null;
    for (int i = 0; i < 10; i++)
    {
        name = function(dictionary);
    }
    DateTime end = DateTime.Now;
    var duration = end.Subtract(start);
    return string.Format("{0} took {1} seconds", name, duration.TotalSeconds);
}

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 ?

  • Vermeiden Sie das Durchlaufen eines Wörterbuchs, wenn Sie können. Diese sind wesentlich langsamer als das Durchlaufen eines Arrays mit denselben Daten.
  • Wenn Sie sich dafür entscheiden, ein Wörterbuch zu durchlaufen, versuchen Sie nicht, zu klug zu sein, obwohl Sie langsamer viel schlechter abschneiden könnten als mit der Standardmethode foreach.

11
Sie sollten mit etwas wie StopWatch anstelle von DateTime messen: hanselman.com/blog/…
Auch Mien

2
Könnten Sie bitte Ihr Testszenario beschreiben, wie viele Elemente in Ihrem Wörterbuch enthalten sind, wie oft Sie Ihr Szenario ausgeführt haben, um die durchschnittliche Zeit zu berechnen, ...
WiiMaxx

3
Interessanterweise erhalten Sie unterschiedliche Ergebnisse, je nachdem, welche Daten Sie im Wörterbuch haben. Beim Durchlaufen des Wörterbuchs muss die Enumerator-Funktion viele leere Slots im Wörterbuch überspringen, was dazu führt, dass es langsamer ist als das Durchlaufen eines Arrays. Wenn das Wörterbuch voll ist, müssen weniger leere Slots übersprungen werden als wenn es halb leer ist.
Martin Brown

26

Es gibt viele Möglichkeiten. Mein persönlicher Favorit ist von KeyValuePair

Dictionary<string, object> myDictionary = new Dictionary<string, object>();
// Populate your dictionary here

foreach (KeyValuePair<string,object> kvp in myDictionary)
{
     // Do some interesting things
}

Sie können auch die Schlüssel- und Wertesammlungen verwenden


14

Mit .NET Framework 4.7kann man Zersetzung verwenden

var fruits = new Dictionary<string, int>();
...
foreach (var (fruit, number) in fruits)
{
    Console.WriteLine(fruit + ": " + number);
}

System.ValueTuple NuGet packageFügen Sie irgendwo hinzu und schreiben Sie, damit dieser Code in niedrigeren C # -Versionen funktioniert

public static class MyExtensions
{
    public static void Deconstruct<T1, T2>(this KeyValuePair<T1, T2> tuple,
        out T1 key, out T2 value)
    {
        key = tuple.Key;
        value = tuple.Value;
    }
}

9
Das ist falsch. .NET 4.7 ist einfach ValueTupleintegriert. Es ist als Nuget-Paket für frühere Versionen verfügbar. Noch wichtiger ist, dass C # 7.0+ benötigt wird, damit die DeconstructMethode als Dekonstruktor für funktioniert var (fruit, number) in fruits.
David Arno

13

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:

public static void Deconstruct<TKey, TVal>(this KeyValuePair<TKey, TVal> pair, out TKey key, out TVal value)
{
   key = pair.Key;
   value = pair.Value;
}

Iterieren Sie über eine Dictionary<TKey, TVal>der folgenden Methoden

// Dictionary can be of any types, just using 'int' and 'string' as examples.
Dictionary<int, string> dict = new Dictionary<int, string>();

// Deconstructor gets called here.
foreach (var (key, value) in dict)
{
   Console.WriteLine($"{key} : {value}");
}

10

Sie haben unten vorgeschlagen, zu iterieren

Dictionary<string,object> myDictionary = new Dictionary<string,object>();
//Populate your dictionary here

foreach (KeyValuePair<string,object> kvp in myDictionary) {
    //Do some interesting things;
}

Zu Ihrer Information, foreachfunktioniert nicht, wenn der Wert vom Typ Objekt ist.


4
Bitte erläutern Sie: Funktioniert foreachnicht, wenn welcher Wert vom Typ ist object? Ansonsten macht das nicht viel Sinn.
Marc L.

9

Einfachste Form zum Iterieren eines Wörterbuchs:

foreach(var item in myDictionary)
{ 
    Console.WriteLine(item.Key);
    Console.WriteLine(item.Value);
}

9

Fügen Sie mit C # 7 diese Erweiterungsmethode zu jedem Projekt Ihrer Lösung hinzu:

public static class IDictionaryExtensions
{
    public static IEnumerable<(TKey, TValue)> Tuples<TKey, TValue>(
        this IDictionary<TKey, TValue> dict)
    {
        foreach (KeyValuePair<TKey, TValue> kvp in dict)
            yield return (kvp.Key, kvp.Value);
    }
}


Und verwenden Sie diese einfache Syntax

foreach (var(id, value) in dict.Tuples())
{
    // your code using 'id' and 'value'
}


Oder dieses, wenn Sie es vorziehen

foreach ((string id, object value) in dict.Tuples())
{
    // your code using 'id' and 'value'
}


Anstelle des Traditionellen

foreach (KeyValuePair<string, object> kvp in dict)
{
    string id = kvp.Key;
    object value = kvp.Value;

    // your code using 'id' and 'value'
}


Die Erweiterungsmethode verwandelt die KeyValuePairvon Ihnen IDictionary<TKey, TValue>in eine stark typisierte Methode tuple, 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 in tuples, sodass diesbezüglich keine Leistungsprobleme bestehen.

Es gibt nur geringe Kosten für das Aufrufen der Erweiterungsmethode zum Erstellen eines tupleim Vergleich zur KeyValuePairdirekten Verwendung, was KEIN Problem sein sollte, wenn Sie die KeyValuePairEigenschaften des ' Keyund Valueohnehin 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


1
Was wäre der Grund, "bequeme" Tupel Schlüssel-Wert-Paaren vorzuziehen? Ich sehe hier keinen Gewinn. Ihr Tupel enthält einen Schlüssel und einen Wert, ebenso das Schlüssel-Wert-Paar.
Maarten

4
Hallo Maarten, danke für deine Frage. Der Hauptvorteil ist die Lesbarkeit des Codes ohne zusätzlichen Programmieraufwand. Bei KeyValuePair muss immer das Formular kvp.Keyund kvp.Valuefü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 als factoryNameund den Wert als benennen models, 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! ;-)
sɐunıɔ ןɐ qɐp

7

Ich weiß, dass dies eine sehr alte Frage ist, aber ich habe einige Erweiterungsmethoden erstellt, die nützlich sein könnten:

    public static void ForEach<T, U>(this Dictionary<T, U> d, Action<KeyValuePair<T, U>> a)
    {
        foreach (KeyValuePair<T, U> p in d) { a(p); }
    }

    public static void ForEach<T, U>(this Dictionary<T, U>.KeyCollection k, Action<T> a)
    {
        foreach (T t in k) { a(t); }
    }

    public static void ForEach<T, U>(this Dictionary<T, U>.ValueCollection v, Action<U> a)
    {
        foreach (U u in v) { a(u); }
    }

Auf diese Weise kann ich Code wie folgt schreiben:

myDictionary.ForEach(pair => Console.Write($"key: {pair.Key}, value: {pair.Value}"));
myDictionary.Keys.ForEach(key => Console.Write(key););
myDictionary.Values.ForEach(value => Console.Write(value););

6

Wenn Sie nur die Werte aufzählen müssen, verwenden Sie manchmal die Wertsammlung des Wörterbuchs:

foreach(var value in dictionary.Values)
{
    // do something with entry.Value only
}

Dieser Beitrag berichtet, dass dies die schnellste Methode ist: http://alexpinsker.blogspot.hk/2010/02/c-fastest-way-to-iterate-over.html


+1 für die Leistungssteigerung. In der Tat bedeutet das Durchlaufen des Wörterbuchs selbst einen gewissen Overhead, wenn Sie nur Werte benötigen. Dies liegt hauptsächlich am Kopieren von Werten oder Referenzen in KeyValuePair-Strukturen.
Jaanus Varus

1
Zu Ihrer Information, der letzte Test in diesem Link ist das Falsche: Er misst die Iteration über die Schlüssel, wobei Werte ignoriert werden, während die beiden vorherigen Tests den Wert verwenden.
Crescent Fresh

5

Ich habe diese Methode in der Dokumentation für die DictionaryBase-Klasse auf MSDN gefunden:

foreach (DictionaryEntry de in myDictionary)
{
     //Do some stuff with de.Value or de.Key
}

Dies war die einzige, die in einer Klasse, die von der DictionaryBase geerbt wurde, ordnungsgemäß funktionieren konnte.


3
Dies sieht aus wie bei Verwendung der nicht generischen Version von Dictionary ... dh vor .NET Framework 2.0.
Joedotnot

@ joed0tnot: Es ist die nicht- Hashtable
generische

5

foreachist am schnellsten und wenn Sie nur iterieren ___.Values, ist es auch schneller

Geben Sie hier die Bildbeschreibung ein


Warum rufst du ContainsKey()die forVersion 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 Sie dicteinen zusammenhängenden Bereich von Ganzzahlen von 0bis enthalten dictCount - 1, wissen Sie, dass der Indexer nicht fehlschlagen kann. Andernfalls dict.Keyssollten Sie iterieren. So oder so, nein ContainsKey()/ TryGetValue()nötig. Zuletzt veröffentlichen Sie bitte keine Screenshots des Codes.
Speck

3

Ich werde den Vorteil von .NET 4.0+ nutzen und eine aktualisierte Antwort auf die ursprünglich akzeptierte geben:

foreach(var entry in MyDic)
{
    // do something with entry.Value or entry.Key
}

3

Die Standardmethode zum Durchlaufen eines Wörterbuchs laut offizieller Dokumentation zu MSDN lautet:

foreach (DictionaryEntry entry in myDictionary)
{
     //Read entry.Key and entry.Value here
}

2

Ich habe eine Erweiterung geschrieben, um ein Wörterbuch zu durchlaufen.

public static class DictionaryExtension
{
    public static void ForEach<T1, T2>(this Dictionary<T1, T2> dictionary, Action<T1, T2> action) {
        foreach(KeyValuePair<T1, T2> keyValue in dictionary) {
            action(keyValue.Key, keyValue.Value);
        }
    }
}

Dann können Sie anrufen

myDictionary.ForEach((x,y) => Console.WriteLine(x + " - " + y));

Sie haben eine ForEachMethode definiert , mit der Sie foreach (...) { }... Scheint unnötig.
Maarten

1

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.

public new IEnumerator<T> GetEnumerator()
{
   return this.Values.GetEnumerator();
}

1

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:

Dictionary<String, Double> myProductPrices = new Dictionary<String, Double>();

//Add some entries to the dictionary

myProductPrices.ToList().ForEach(kvP => 
{
    kvP.Value *= 1.15;
    Console.Writeline(String.Format("Product '{0}' has a new price: {1} $", kvp.Key, kvP.Value));
});

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.

var newProductPrices = myProductPrices.Select(kvp => new { Name = kvp.Key, Price = kvp.Value * 1.15 } );

5
Kopieren Sie die ganze Sammlung ohne ersichtlichen Grund wird nicht die Leistung verbessern. Dies verlangsamt den Code erheblich und verdoppelt den Speicherbedarf des Codes, der praktisch keinen zusätzlichen Speicher verbrauchen sollte.
Servy

Ich vermeide die Nebenwirkungsmethode 'List.ForEach': Erzwingt die foreachSichtbarkeit von Nebeneffekten, wo sie hingehört .
user2864740

0
var dictionary = new Dictionary<string, int>
{
    { "Key", 12 }
};

var aggregateObjectCollection = dictionary.Select(
    entry => new AggregateObject(entry.Key, entry.Value));

2
Diese Antwort muss mehr Rechtfertigung / Beschreibung enthalten. Was trägt AggregateObjectdazu bei KeyValuePair? Wo ist die "Iteration", wie in der Frage gefordert?
Marc L.

Wählen Sie iteriert über das Wörterbuch und ermöglicht es uns, an jedem Objekt zu arbeiten. Es ist nicht so allgemein wie foreach, aber ich habe es oft benutzt. Hat meine Antwort wirklich eine Ablehnung verdient?
Pixar

Nein, 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ßlich Select. Das Lambda läuft erst, wenn aggregateObjectCollectiones tatsächlich aufgezählt ist. Wenn diese Antwort als "erster Weg" genommen wird (dh vor einer Geraden verwendet wird foreach), 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.
Marc L.

0

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.

Dictionary<int, string> dict = new Dictionary<int, string>();
dict.Add(1,"One");
dict.Add(2,"Two");
dict.Add(3,"Three");

foreach (KeyValuePair<int, string> item in dict)
{
    Console.WriteLine("Key: {0}, Value: {1}", item.Key, item.Value);
}

0

Wenn Sie die for-Schleife verwenden möchten, können Sie dies tun:

var keyList=new List<string>(dictionary.Keys);
for (int i = 0; i < keyList.Count; i++)
{
   var key= keyList[i];
   var value = dictionary[key];
 }

Was ist der Vorteil davon? Es ist längerer Code als eine foreachSchleife und schlechtere Leistung, da new List<string>(dictionary.Keys)die dictionary.CountZeiten 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 .
Speck

Wenn Sie über eine große Sammlung verfügen und die Vorgänge nur langsam ausgeführt werden und sich Ihre Sammlung beim Iterieren ändern kann, werden Sie vor dem Fehler "Sammlung hat sich geändert" geschützt, und diese Lösung bietet eine bessere Leistung als die Verwendung von ElementAt.
Seçkin Durgay

Ich bin damit einverstanden, dass das Vermeiden von Ausnahmen "Sammlung wurde geändert" ein Grund dafür ist, obwohl dieser Sonderfall in der Frage nicht angegeben wurde und man es immer tun könnte 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.
Speck

Ja, Sie haben Recht, aber es gibt hier eine Antwort mit ElementAt und es hat ein sehr hohes Ansehen und ich habe diese Antwort eingegeben :)
Seçkin Durgay

0

Wie bereits in dieser Antwort erwähnt , wird KeyValuePair<TKey, TValue>eine DeconstructMethode 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 KeyValuePairagnostische Weise zu durchlaufen :

var dictionary = new Dictionary<int, string>();

// ...

foreach (var (key, value) in dictionary)
{
    // ...
}

-1

einfach mit linq

 Dictionary<int, string> dict = new Dictionary<int, string>();
 dict.Add(1, "American Ipa");
 dict.Add(2, "Weiss");
 dict.ToList().ForEach(x => Console.WriteLine($"key: {x.Key} | value: {x.Value}") );

Ich sehe, dass Sie anrufen, ToList()weil dies ForEach()nur für die List<>Klasse definiert ist , aber warum tun Sie das alles anstatt nur foreach (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.
Speck

Nur um der Code-Visualisierung willen könnte es wirklich so gemacht werden, wie Sie es angegeben haben. Ich wollte es nur auf eine andere Art und Weise präsentieren und aus meiner schlankeren Sicht entschuldige ich mich dafür, dass ich die angegebene Antwort nicht gesehen habe, eine Umarmung
Luiz Fernando Corrêa Leite

-3

Zusätzlich zu den am höchsten bewerteten Posts, in denen eine Diskussion zwischen der Verwendung besteht

foreach(KeyValuePair<string, string> entry in myDictionary)
{
    // do something with entry.Value or entry.Key
}

oder

foreach(var entry in myDictionary)
{
    // do something with entry.Value or entry.Key
}

Am vollständigsten ist Folgendes, da Sie den Wörterbuchtyp anhand der Initialisierung sehen können. Kvp ist KeyValuePair

var myDictionary = new Dictionary<string, string>(x);//fill dictionary with x

foreach(var kvp in myDictionary)//iterate over dictionary
{
    // do something with kvp.Value or kvp.Key
}

5
Das Erstellen und Kopieren eines zweiten Wörterbuchs ist keine gültige Lösung für die Lesbarkeit von Code. Tatsächlich würde ich argumentieren, dass dies das Verständnis des Codes erschweren würde, da Sie sich jetzt fragen müssen: "Warum hat der letzte ein zweites Wörterbuch erstellt?" Wenn Sie ausführlicher sein möchten, verwenden Sie einfach Option eins.
Matthew Goulart

Ich wollte Ihnen nur zeigen, dass die Verwendung im foreach aus der Erklärung hervorgeht
BigChief
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.