tags:

views:

143

answers:

4

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)
A: 

Im not sure if there is a method like you ask for, but you could write a small function for it, or use the try catch exception, presumably if you try adding a value that already exists it will throw an exception. If you catch that and ignore it... Just a suggestion

Charles Gargent
+1  A: 

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

Darin Dimitrov
+8  A: 

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);
}
Evgeny
+5  A: 

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.

Jon Skeet