2010-04-12 5 views
31

Ich bin krank von Code-Blöcken, wie dies für verschiedene Teile des Codes zu tun ich habe:.net Wörterbuch und Lookup-add/update

if (dict.ContainsKey[key]) { 
    dict[key] = value; 
} 
else { 
    dict.Add(key,value); 
} 

und für Lookups (dh Schlüssel -> Liste des Wertes)

Gibt es eine andere Sammlung Lib oder Erweiterung-Methode, die ich verwenden sollte, um dies in einer Zeile von Code zu tun, egal was die Schlüssel-und Werttypen sind?

z.B.

dict.AddOrUpdate(key,value) 
lookup.AddOrUpdate(key,value) 
+0

Ist 'Lookup' ein' ILookup '? Ich denke nicht, weil es keine 'ContainsKey'-Methode haben sollte. Ich bestätige nur, dass .NET die Suche nicht verändert hat, weil ich nach einem Weg gesucht habe, ein "ILookup" zu aktualisieren ... – drzaus

Antwort

32

Wie Evgeny sagt, wird der Indexer ersetzen bereits Werte vorhanden - wenn Sie also nur bedingungslos den Wert für einen bestimmten Schlüssel einstellen möchten, können Sie tun

dictionary[key] = value; 

Der interessantere Fall ist der "hole einen Wert, oder füge ihn bei Bedarf ein". Es ist einfach, mit einer Erweiterung Methode zu tun:

public static TValue GetOrCreateValue<TKey, TValue> 
    (this IDictionary<TKey, TValue> dictionary, 
    TKey key, 
    TValue value) 
{ 
    return dictionary.GetOrCreateValue(key,() => value); 
} 

public static TValue GetOrCreateValue<TKey, TValue> 
    (this IDictionary<TKey, TValue> dictionary, 
    TKey key, 
    Func<TValue> valueProvider) 
{ 
    TValue ret; 
    if (!dictionary.TryGetValue(key, out ret)) 
    { 
     ret = valueProvider(); 
     dictionary[key] = ret; 
    } 
    return ret; 
} 

Beachten Sie die Verwendung eines Delegierten den Standardwert zu schaffen - die man Szenarien wie die „Liste als Wert“ erleichtert; Sie wollen nicht auf die leere Liste erstellen, es sei denn Sie müssen:

dict.GetOrCreateValue(key,() => new List<int>()).Add(item); 

Beachten Sie auch, wie dies nur die Lookup einmal durchführt, wenn der Schlüssel bereits vorhanden ist - es gibt keine Notwendigkeit eine ContainsKey und dann Blick zu tun up den Wert. Es erfordert jedoch immer noch zwei Lookups, wenn es den neuen Wert erstellt.

1

Ich bin nicht sicher, ob es ein Verfahren ist, wie man sich nur wünschen, aber man konnte eine kleine Funktion für sie, oder verwenden Sie die Try-Catch Ausnahme schreiben, vermutlich, wenn Sie versuchen, einen Wert hinzu, dass es bereits existiert, wird werfen eine Ausnahme. Wenn Sie das fangen und es ignorieren ... Nur ein Vorschlag

4

ConcurrentDictionary in .NET 4.0 hat this nice method. Sie könnten auch eine Erweiterungsmethode dafür schreiben.

14

Beim Aktualisieren müssen Sie keine Überprüfung durchführen. Einfach verwenden:

dict[key] = value 

Es wird jeden vorhandenen Wert ersetzen. Beim Abrufen des Wertes gibt es leider keine einfache Methode (wie setdefault in Python), aber Sie könnten Ihre eigene Erweiterungsmethode erstellen. Etwas wie folgt aus:

if (!lookup.TryGetValue(key, out value)) 
{ 
    value = new List<T>(); 
    lookup.Add(key, value); 
} 
3

Wenn mit .NET Framework 4 oder höher arbeiten, können Sie die AddOrUpdate Method

dict.AddOrUpdate(key,value) 

hinzuzufügen oder zu aktualisieren ist wie dieser

dict[key] = value; 
+4

Dies ist nur für 'ConcurrentDictionary' verfügbar. – Mrchief

+0

Ja, Sie verwenden es mit Concurrent Dictionary, weil Sie nicht ' Ich möchte in eine Falle fallen, in der du die Add-Bedingung checkst, feststellst, dass du eine Add-Operation durchführen musst, und dann etwas anderes tun musst, um hinter deinem Rücken zu addieren. AddOrUpdate macht es atomar, glaube ich. – quillbreaker

0

verwenden Ich mag AddOrUpdate Methode von ConcurrentDictionary, aber ich mag Leistung der Dictionary-Sammlung zu :) Also, das ist die Erweiterungsmethode für alle Klassen, die IDictionary implementieren.

public static TValue AddOrUpdate<TKey, TValue>(
    this IDictionary<TKey, TValue> dict, 
    TKey key, 
    TValue addValue, 
    Func<TKey, TValue, TValue> updateValueFactory) 
{ 
    TValue existing; 
    if (dict.TryGetValue(key, out existing)) 
    { 
     addValue = updateValueFactory(key, existing); 
     dict[key] = addValue; 
    } 
    else 
    { 
     dict.Add(key, addValue); 
    } 

    return addValue; 
} 


public static TValue AddOrUpdate<TKey, TValue>(
    this IDictionary<TKey, TValue> dict, 
    TKey key, 
    Func<TKey, TValue> addValueFactory, 
    Func<TKey, TValue, TValue> updateValueFactory) 
{ 
    TValue existing; 
    if (dict.TryGetValue(key, out existing)) 
    { 
     existing = updateValueFactory(key, existing); 
     dict[key] = existing; 
    } 
    else 
    { 
     existing = addValueFactory(key); 
     dict.Add(key, existing); 
    } 

    return existing; 
} 
Verwandte Themen