开发者

C#: Does a dictionary in C# have something similar to the Python setdefault?

Trying to translate some methods written in Python over into C#. The line looks like this:

d[p] = d.setdefault(p, 0) + 1
开发者_开发百科

What exactly does setdefault do? And is there anything similar I can use in a C# dictionary? Or rather, how can I translate that line into C#?


From the Python docs:

setdefault(key[, default])

If key is in the dictionary, return its value. If not, insert key with a value of default and return default. default defaults to None.

There is no direct implementation of this in the .NET framework, but you can define an extension method:

public static V SetDefault<K,V>(this IDictionary<K,V> dict, K key, V @default)
{
    V value;
    if (!dict.TryGetValue(key, out value))
    {
        dict.Add(key, @default);
        return @default;
    }
    else
    {
        return value;
    }
}

Usage:

string key;
Dictionary<string, int> dict;

dict[key] = dict.SetDefault(key, 0) + 1;


Edit -- warning: the following works only for this specific case, not for the general case -- see below.

int value = 0;
d.TryGetValue(p, out value);
d[p] = value + 1;

this is equivalent to the following Python snippet (which is better than the one you show):

d[p] = d.get(p, 0) + 1

setdefault is like get (fetch if present, else use some other value) plus the side effect of injecting the key / other value pair in the dict if the key wasn't present there; but here this side effect is useless, since you're about to assign d[p] anyway, so using setdefault in this case is just goofy (complicates things and slow you down to no good purpose).

In C#, TryGetValue, as the name suggests, tries to get the value corresponding to the key into its out parameter, but, if the key's not present, then it (warning: the following phrase is not correct:) just leaves said value alone (edit:) What it actually does if the key's not present is not to "leave the value alone" (it can't, since it's an out value; see the comments), but rather to set it to the default value for the type -- here, since 0 (the default value) is what we want, we're fine, but this doesn't make TryGetValue a general-purpose substitute for Python's dict.get.

TryGetValue also returns a boolean result, telling you whether it did manage to get the value or not, but you don't need it in this case (just because the default behavior happens to suit us). To build the general equivalent of Python's dict.get, you need another idiom:

if (!TryGetValue(d, k)) {
  k = whatyouwant;
}

Now this idiom is indeed the general-purpose equivalent to Python's k = d.get(k, whatyouwant).


If you want to have the item default to the default instance of object, you might want to consider this (from here)

public static TValue SetDefault<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key) 
{ 
  TValue result; 
  if (!dictionary.TryGetValue(key, out result)) 
  { 
    return dictionary[key] = (TValue)Activator.CreateInstance(typeof(TValue)); 
  } 
  return result; 
} 

This leads to the rather nice syntax of:

var children = new Dictionary<string, List<Node>>();
d.SetDefault(“left”).Add(childNode);


d.setdefault(p, 0) will return the value of the entry with key p if it exists and if it does not then it will set the value for the key p to 0.


I know I'm 3 years late to the party, but a variation that works and is useful:

public static TV SetDefault<TK, TV>(this IDictionary<TK, TV> dict, TK key) where TV: new() {
    TV value;
    if (!dict.TryGetValue(key, out value)) dict.Add(key, value = new TV());
    return value;
}

That is, for value types that can be initialized without a parameter, do so.

var lookup = new Dictionary<string, HashSet<SomeType>>();
lookup.SetDefault("kittens").Add(mySomeType);
0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜