2010-04-12 11 views
31

Sono stufo di fare blocchi di codice come questo per vari pezzi di codice che ho:dizionario .net e ricerca add/update

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

e per le ricerche (cioè chiave -> elenco di valori)

if (lookup.ContainsKey[key]) { 
    lookup[key].Add(value); 
} 
else { 
    lookup.Add(new List<valuetype>); 
    lookup[key].Add(value); 
} 

Esiste un altro metodo di estensione lib o di estensione che dovrei usare per farlo in una riga di codice, indipendentemente dal tipo di chiave e valore?

ad es.

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

È 'lookup' un' ILookup '? Sto pensando non perché non dovrebbe avere un metodo 'ContainsKey'. Confermando che .NET non ha cambiato le ricerche dopo la domanda, perché cercava un modo per aggiornare un 'ILookup' ... – drzaus

risposta

32

Come dice Evgeny, l'indicizzatore sarà già sostituire i valori esistenti - quindi se solo desidera impostare incondizionatamente il valore per una data chiave, si può fare

dictionary[key] = value; 

Il caso più interessante è "ottieni un valore o inseriscilo se necessario". E 'facile da fare con un metodo di estensione:

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

Nota l'uso di un delegato per creare il valore di default - che facilita gli scenari come la "lista come valore" uno; non si vuole creare una lista vuota se non si dispone di:

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

Si noti inoltre come questo esegue solo la ricerca una volta, se la chiave è già presente - non c'è bisogno di fare uno sguardo ContainsKey e poi aumenta il valore. Tuttavia richiede ancora due ricerche quando si crea il nuovo valore.

1

Im non sicuro se c'è un metodo come si chiede, ma si potrebbe scrivere una piccola funzione per esso, o utilizzare l'eccezione try catch, presumibilmente se si tenta di aggiungere un valore che già esiste si getterà un'eccezione. Se lo prendi e lo ignori ... Solo un suggerimento

4

ConcurrentDictionary in .NET 4.0 ha this nice method. Potresti anche scrivere un metodo di estensione per questo.

14

Durante l'aggiornamento non è necessario eseguire un controllo. Utilizzare semplicemente:

dict[key] = value 

andrà a sostituire qualsiasi valore esistente. Quando si recupera il valore, sfortunatamente non esiste un metodo singolo conveniente (come setdefault in Python), ma è possibile creare il proprio metodo di estensione. Qualcosa di simile a questo:

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

Se si lavora con .NET Framework 4 o successivo, è possibile utilizzare l'AddOrUpdate Method

dict.AddOrUpdate(key,value) 

o l'aggiornamento è come questo

dict[key] = value; 
+4

Questo è disponibile solo per' ConcurrentDictionary' – Mrchief

+0

Sì, lo si usa con Dizionario Concurrent perché non si usa ' Voglio cadere in una trappola in cui controlli la condizione di aggiunta, stabilisci che devi fare un add, quindi qualcos'altro da aggiungere alle tue spalle. AddOrUpdate lo rende atomico, credo. – quillbreaker

0

mi piace AddOrUpdate metodo ConcurrentDictionary, ma mi piace prestazioni della raccolta di dizionari troppo :) Quindi, questo è il metodo di estensione per tutte le classi che implementano IDictionary.

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