Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.net dictionary and lookup add / update

Tags:

c#

collections

I am sick of doing blocks of code like this for various bits of code I have:

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

and for lookups (i.e. key -> list of value)

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

Is there another collections lib or extension method I should use to do this in one line of code no matter what the key and value types are?

e.g.

dict.AddOrUpdate(key,value)  
lookup.AddOrUpdate(key,value)
like image 982
freddy smith Avatar asked Apr 12 '10 07:04

freddy smith


3 Answers

As Evgeny says, the indexer will already replace existing values - so if you just want to unconditionally set the value for a given key, you can do

dictionary[key] = value;

The more interesting case is the "get a value, or insert it if necessary". It's easy to do with an extension method:

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

Note the use of a delegate to create the default value - that facilitates scenarios like the "list as value" one; you don't want to create the empty list unless you have to:

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

Also note how this only performs the lookup once if the key is already present - there's no need to do a ContainsKey and then look up the value. It still requires two lookups when it's creating the new value though.

like image 77
Jon Skeet Avatar answered Oct 18 '22 18:10

Jon Skeet


When updating you don't need to perform a check. Simply use:

dict[key] = value

It will replace any existing value. When retrieving the value unfortunately there is no convenient single method (like setdefault in Python), but you could make your own extension method. Something like this:

if (!lookup.TryGetValue(key, out value))
{
     value = new List<T>();
     lookup.Add(key, value);
}
like image 17
EMP Avatar answered Oct 18 '22 18:10

EMP


ConcurrentDictionary in .NET 4.0 has this nice method. You could also write an extension method for this.

like image 4
Darin Dimitrov Avatar answered Oct 18 '22 18:10

Darin Dimitrov