c# loop Wie kann ich ein Wörterbuch am besten durchlaufen?




c# keyvaluepair (20)

Die Standardmethode zum Durchlaufen eines Dictionarys gemäß der offiziellen Dokumentation zu MSDN ist:

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

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


Ich werde den Vorteil 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
}

Ich wollte nur 2 Cent hinzufügen, da sich die meisten Antworten auf die foreach-Schleife 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 geringfügigen Leistungsverbesserung kommen (wie hier bei foreach vs someList.Foreach () {} ) hervorgehoben, insbesondere wenn mit großen Wörterbüchern gearbeitet wird und parallel ausgeführt wird Option / hat überhaupt keinen Effekt.

Beachten Sie auch, dass Sie der 'Value'-Eigenschaft innerhalb 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 } );


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

Einfachstes Formular zum Durchlaufen eines Wörterbuchs:

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

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

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

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

Wenn Sie nur die Sammlung 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 ein optionales C # 3.0 und höher ist. Sie können hier auch den genauen Typ Ihrer Schlüssel / Werte verwenden.)


Dictionary <TKey, TValue> Dies ist eine generische Collection-Klasse 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. Jedes Element im Wörterbuch ist Wird als KeyValuePair <TKey, TValue> -Struktur behandelt, die einen Schlüssel und seinen Wert darstellt. Daher sollten wir den Elementtyp KeyValuePair <TKey, TValue> während der Iteration des Elements 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);
}

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

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

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

Beispiel:

Erstellen Sie eine Erweiterungsmethode auf 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 jedes 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}");
}

Mit .NET Framework 4.7 kann eine Zerlegung verwendet werden

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

System.ValueTuple NuGet package Sie das System.ValueTuple NuGet package und schreiben Sie irgendwo, damit dieser Code auf niedrigeren C # -Versionen ausgeführt werden kann

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

Kommt drauf an, ob Sie nach den Schlüsseln oder den Werten suchen ...

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

Wörterbücher sind spezielle Listen, wobei jeder Wert in der Liste einen Schlüssel hat, der auch eine Variable ist. Ein gutes Beispiel für ein Wörterbuch ist ein Telefonbuch.

   Dictionary<string, long> phonebook = new Dictionary<string, long>();
    phonebook.Add("Alex", 4154346543);
    phonebook["Jessica"] = 4159484588;

Beachten Sie, dass bei der Definition eines Wörterbuchs eine generische Definition mit zwei Typen bereitgestellt werden muss - dem Typ des Schlüssels und dem Typ des Werts. In diesem Fall ist der Schlüssel eine Zeichenfolge, während der Wert eine ganze Zahl ist.

Es gibt auch zwei Möglichkeiten, einen einzelnen Wert zum Wörterbuch hinzuzufügen, entweder mit dem Klammeroperator oder mit der Add-Methode.

Um zu überprüfen, ob ein Wörterbuch einen bestimmten Schlüssel enthält, können wir die Methode ContainsKey verwenden:

Dictionary<string, long> phonebook = new Dictionary<string, long>();
phonebook.Add("Alex", 415434543);
phonebook["Jessica"] = 415984588;

if (phonebook.ContainsKey("Alex"))
{
    Console.WriteLine("Alex's number is " + phonebook["Alex"]);
}

Um ein Element aus einem Wörterbuch zu entfernen, können Sie die Remove-Methode verwenden. Ein Element mit seinem Schlüssel aus einem Wörterbuch zu entfernen, ist schnell und sehr effizient. Wenn Sie ein Element mit seinem Wert aus einer Liste entfernen, ist der Vorgang im Gegensatz zu der Funktion zum Entfernen des Wörterbuchs langsam und ineffizient.

Dictionary<string, long> phonebook = new Dictionary<string, long>();
phonebook.Add("Alex", 415434543);
phonebook["Jessica"] = 415984588;

phonebook.Remove("Jessica");
Console.WriteLine(phonebook.Count);

zusätzlich zu den höchstrangigen Beiträgen, bei denen eine Diskussion zwischen der Verwendung stattfindet

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

Wenn Sie beispielsweise die Wertesammlung standardmäßig durchlaufen möchten, können Sie IEnumerable <> implementieren, wobei T der Typ des Wertobjekts im Wörterbuch ist und "this" ein Dictionary ist.

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

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

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

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

FYI, foreach funktioniert nicht, wenn der Wert vom Typ object ist.


Ich schätze, dass diese Frage bereits viele Antworten hatte, aber ich wollte etwas Forschung einbringen.

Das Durchlaufen eines Wörterbuchs kann relativ langsam sein, verglichen mit dem Durchlaufen eines Arrays. In meinen Tests dauerte eine Iteration über ein Array 0.015003 Sekunden, wohingegen eine Iteration über ein Wörterbuch (mit der gleichen Anzahl von Elementen) 0.0365073 Sekunden dauerte, also 2,4 mal so lang! Obwohl ich viel größere Unterschiede gesehen habe. Zum Vergleich lag eine Liste irgendwo dazwischen bei 0,00215043 Sekunden.

Dies ist jedoch vergleichbar mit Äpfeln und Orangen. Mein Punkt ist, dass das Durchlaufen von Wörterbüchern langsam ist.

Wörterbücher sind für Suchvorgänge optimiert. Deshalb habe ich zwei Methoden entwickelt. Der eine führt einfach eine foreach durch, der andere iteriert die Schlüssel und schaut dann auf.

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

    return "Normal";
}

Dieses lädt die Schlüssel und iteriert stattdessen über sie (ich habe auch versucht, die Schlüssel in einen String [] 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";
}

Bei diesem Beispiel wurden für den normalen foreach-Test 0,0310062 und für die Schlüsselversion 0,2205441 verwendet. Das Laden aller Schlüssel und das Durchlaufen aller Suchvorgänge ist deutlich langsamer!

Für einen abschließenden Test habe ich zehnmal meine Iteration durchgeführt, um zu sehen, ob die Verwendung der Tasten hier Vorteile hat (bis jetzt war ich nur neugierig):

Hier ist die RunTest-Methode, wenn Sie sich anschaulich machen, 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 Foreach-Lauf 0,2820564 Sekunden (etwa zehnmal länger als eine einzelne Iteration - wie Sie es erwarten würden). Die Iteration über die Tasten dauerte 2.2249449 Sekunden.

Zum Hinzufügen hinzugefügt: Nachdem ich einige der anderen Antworten gelesen hatte, fragte ich mich, was passieren würde, wenn ich Dictionary anstelle von Dictionary verwende. In diesem Beispiel dauerte das Array 0.0120024 Sekunden, die Liste 0.0185037 Sekunden und das Wörterbuch 0,0465093 Sekunden. Man kann davon ausgehen, dass der Datentyp einen Unterschied macht, wie viel langsamer das Wörterbuch ist.

Was sind meine Schlussfolgerungen ?

  • Vermeiden Sie das Durchlaufen eines Wörterbuchs, wenn Sie können, da diese wesentlich langsamer sind als ein Array mit den gleichen Daten.
  • Wenn Sie sich entscheiden, ein Wörterbuch zu durchlaufen, sollten Sie nicht zu schlau sein, auch wenn Sie langsamer sind, als Sie die Standardmethode foreach verwenden.

Im Allgemeinen ist die Frage nach der "besten Art" ohne einen bestimmten Kontext wie die Frage nach der besten Farbe.

Einerseits gibt es viele Farben und es gibt keine beste Farbe. Das hängt von den Bedürfnissen und oft auch vom Geschmack ab.

Auf der anderen Seite gibt es viele Möglichkeiten, ein Dictionary in C # zu durchlaufen, und es gibt keine beste Methode. Das hängt von den Bedürfnissen und oft auch vom Geschmack ab.

Der einfachste Weg

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

Wenn Sie nur den Wert benötigen (können Sie ihn als item aufrufen, ist er 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 überrascht über die Reihenfolge der Aufzählung eines Wörterbuchs.

LINQ bietet eine prägnante Syntax, mit der die Reihenfolge (und viele andere Dinge) festgelegt werden kann, z.

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

Wieder benötigen Sie möglicherweise nur den Wert. LINQ bietet auch eine kurze Lösung für:

  • iteriere direkt mit dem Wert (erlaubt das Aufrufen des item , besser lesbar 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)
}

Es gibt viele weitere praktische 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)!





loops