开发者

.net dictionary and lookup add / update

I am sick of doing blocks of code like this for various bits of开发者_如何学Python 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)


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.


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


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


If working with .NET Framework 4 or later, you can use the AddOrUpdate Method

dict.AddOrUpdate(key,value)  

add or update is like this

dict[key] = value;


I like AddOrUpdate method of ConcurrentDictionary, but I like performance of Dictionary collection too :) So, this is extension method for all classes implementing 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;
}


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

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜