it-swarm.com.de

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

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

2346
Jake Stewart
foreach(KeyValuePair<string, string> entry in myDictionary)
{
    // do something with entry.Value or entry.Key
}
3370
Pablo Fernandez

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

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

Wenn Sie nur die Auflistung der Schlüssel durchlaufen müssen, verwenden Sie

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 Schlüsselwort var eine optionale C # 3.0- und höher-Funktion ist. Sie können hier auch den genauen Typ Ihrer Schlüssel/Werte verwenden.)

783
Jacob

In einigen Fällen benötigen Sie möglicherweise einen Zähler, der von der for-Loop-Implementierung bereitgestellt wird. Dafür bietet LINQ ElementAt , das Folgendes ermöglicht:

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

Kommt drauf an, ob du den Schlüsseln oder den Werten nachgehst ...

Aus dem MSDN Dictionary(TKey, TValue) Klassenbeschreibung:

// 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);
}
88
J Healy

Nach dem "besten Weg" ohne einen bestimmten Kontext zu fragen ist im Allgemeinen wie nach was ist die beste Farbe?

Einerseits gibt es viele Farben und es gibt keine beste Farbe. Es kommt auf das Bedürfnis an und oft auch auf den Geschmack.

Auf der anderen Seite gibt es viele Möglichkeiten, ein Dictionary in C # zu durchlaufen, und es gibt keine beste Möglichkeit. Es kommt auf das Bedürfnis an und oft auch auf den Geschmack.

Der einfachste Weg

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

Wenn Sie nur den Wert benötigen (kann item genannt werden, lesbarer 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 kurze Syntax, mit der Sie die Reihenfolge (und viele andere Dinge) angeben 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ägnante Lösung für:

  • iteriere direkt auf dem Wert (erlaubt es, ihn item zu nennen, lesbarer als kvp.Value)
  • aber sortiert nach den tasten

Hier ist es:

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

Anhand dieser Beispiele können Sie noch viele weitere reale Anwendungsfälle ausführen. Wenn Sie keine bestimmte Bestellung benötigen, halten Sie sich einfach an den "einfachsten Weg" (siehe oben)!

76

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

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

Ist es das, wonach du suchst?

47
George Mauer

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
});
36
Onur

Es gibt viele Möglichkeiten. Mein persönlicher Favorit ist 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

25
theo

Ich schätze, dass diese Frage bereits viele Antworten erhalten hat, aber ich wollte ein wenig Nachforschungen anstellen.

Das Durchlaufen eines Wörterbuchs kann im Vergleich zum Durchlaufen eines Arrays sehr 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 dazwischen bei 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 das Nachschlagen optimiert, daher habe ich zwei Methoden erstellt. Einer macht einfach einen foreach, der andere iteriert die Schlüssel und schaut dann nach.

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 hat (zu diesem Zeitpunkt war ich nur neugierig):

Hier ist die RunTest-Methode, mit der Sie sich vorstellen können, was los ist.

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 Vorlauf 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.

Bearbeitet, um hinzuzufügen: Als ich einige der anderen Antworten las, fragte ich mich, was passieren würde, wenn ich Wörterbuch anstelle von Wörterbuch 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, um wie viel langsamer das Wörterbuch ist.

Was sind meine Schlussfolgerungen?

  • Vermeiden Sie es, über ein Wörterbuch zu iterieren, wenn Sie können. Sie sind wesentlich langsamer als das Iterieren über ein Array mit denselben Daten.
  • Wenn Sie ein Wörterbuch durchlaufen möchten, versuchen Sie nicht, zu clever zu sein, auch wenn Sie langsamer sind als mit der Standardmethode foreach.
25
Liath

C # 7.0 eingeführt Dekonstruktoren und wenn Sie .NET Core 2.0 + Anwendung, die Struktur KeyValuePair<> enthält bereits eine Deconstruct() für Sie. Sie können also Folgendes 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}");
}

enter image description here

19
Jaider

Sie schlugen vor, unten 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, foreach funktioniert nicht, wenn der Wert vom Typ object ist.

11
Khushi

Mit .NET Framework 4.7 kann Zerlegung verwendet werden

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

Fügen Sie System.ValueTuple NuGet package hinzu und schreiben Sie irgendwo, 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;
    }
}
11
Pavel

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'
}


An die Stelle 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 wandelt das KeyValuePair Ihres IDictionary<TKey, TValue> in ein stark typisiertes Tuple um, sodass Sie diese neue komfortable Syntax verwenden können.

Die erforderlichen Wörterbucheinträge werden -just- in tuples konvertiert, daher wird NICHT das gesamte Wörterbuch in tuples konvertiert, sodass diesbezüglich keine Leistungsprobleme bestehen.

Die Erweiterungsmethode zum Erstellen einer Tuple muss nur geringfügig aufgerufen werden, im Vergleich zur direkten Verwendung der KeyValuePair. Dies sollte KEIN Problem sein, wenn Sie die Eigenschaften KeyValuePairKey und Value trotzdem einer neuen Schleife zuweisen.

In der Praxis eignet sich diese neue Syntax in den meisten Fällen sehr gut, mit Ausnahme von Ultra-High-Performance-Szenarien auf niedriger Ebene, in denen Sie die Option haben, sie einfach nicht an dieser bestimmten Stelle zu verwenden.

Überprüfen Sie dies: MSDN Blog - Neue Funktionen in C # 7

8

Einfachste Form, um ein Wörterbuch zu iterieren:

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

Wenn Sie nur die aufzuzählenden Werte benötigen, verwenden Sie manchmal die Wertesammlung des Wörterbuchs:

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

Gemeldet von diesem Beitrag, der angibt, dass es die schnellste Methode ist: http://alexpinsker.blogspot.hk/2010/02/c-fastest-way-to-iterate-over.html

6
ender

Ich habe diese Methode in der Dokumentation der DictionaryBase-Klasse auf MSDN gefunden:

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

Dies war die einzige, die ich in einer Klasse, die von DictionaryBase geerbt wurde, zum korrekten Funktionieren bringen konnte.

5
Zannjaminderson

Ab C # 7 können Sie Objekte in Variablen zerlegen. Ich bin der Meinung, dass dies der beste Weg ist, um ein Wörterbuch zu durchlaufen.

Beispiel:

Erstellen Sie eine Erweiterungsmethode für KeyValuePair<TKey, TVal>, die diese dekonstruiert:

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

Durchlaufen Sie jeden Dictionary<TKey, TVal> auf folgende Weise

// 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}");
}
3
Domn Werner

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

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

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

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

Wenn Sie beispielsweise standardmäßig über die Werteauflistung iterieren möchten, können Sie nach meinem Dafürhalten IEnumerable <> implementieren. Dabei ist T der Typ des Wertobjekts im Wörterbuch und "this" ist ein Dictionary.

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

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););
2
boca

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 kannst du anrufen

myDictionary.ForEach((x,y) => Console.WriteLine(x + " - " + y));
1
Steven Delrue
var dictionary = new Dictionary<string, int>
{
    { "Key", 12 }
};

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

Ich wollte nur meine 2 Cent hinzufügen, da sich die meisten Antworten auf foreach-loop beziehen. Bitte werfen Sie einen Blick auf den folgenden Code:

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 gezeigt foreach vs someList.Foreach () {} ), insbesondere bei der Arbeit mit Large Wörterbücher und das parallele Laufen ist keine Option/hat überhaupt keine Auswirkung.

Beachten Sie auch, dass Sie der Eigenschaft 'Value' in einer foreach-Schleife keine Werte zuweisen können. Auf der anderen Seite können Sie auch den 'Key' 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 } );
1
Alex

Dictionary <TKey, TValue> Dies ist eine generische Auflistungsklasse in c # und speichert die Daten im Schlüsselwertformat. Der Schlüssel muss eindeutig sein und darf nicht null sein, wohingegen der Wert doppelt und null sein kann. Da jedes Element im Wörterbuch als KeyValuePair <TKey, TValue> -Struktur behandelt wird, die einen Schlüssel und seinen Wert darstellt. und daher sollten wir den Elementtyp KeyValuePair <TKey, TValue> während der Iteration des Elements nehmen. nten 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

Die drei verschiedenen Methoden zum Durchlaufen des Wörterbuchs.

Methode 1-using for-Schleife

for (int i = 0; i < DemotestDictionary.Count; i++ )
 {
 int key = i;
 string value = DemotestDictionary[i];
 // Do something here
 }

Methode 2 unter Verwendung jeder Iteration

foreach (var entry in DemotestDictionary)
 {
 int key = entry.Key;
 string value = entry.Value;
 // Do something here
 } 

Methode 3 - für jede Iteration mit KeyValuePair

foreach (KeyValuePair<int, string> entry in DemotestDictionary)
 {
 int key = entry.Key;
 string value = entry.Value;
// Do something here
 }
0