Analogue of Python's Defaultdict?

Is there a .NET analogue of Python's defaultdict? I find it useful to write short code, eg. counting frequencies:

>>> words = "to be or not to be".split()
>>> print words
['to', 'be', 'or', 'not', 'to', 'be']
>>> from collections import defaultdict
>>> frequencies = defaultdict(int)
>>> for word in words:
...     frequencies[word] += 1
... 
>>> print frequencies
defaultdict(<type 'int'>, {'not': 1, 'to': 2, 'or': 1, 'be': 2})

So ideally in C# I could write:

var frequencies = new DefaultDictionary<string,int>(() => 0);
foreach(string word in words)
{
    frequencies[word] += 1
}
2

4 Answers

Here's a simple implementation:

public class DefaultDictionary<TKey, TValue> : Dictionary<TKey, TValue> where TValue : new()
{
    public new TValue this[TKey key]
    {
        get
        {
            TValue val;
            if (!TryGetValue(key, out val))
            {
                val = new TValue();
                Add(key, val);
            }
            return val;
        }
        set { base[key] = value; }
    }
}

And how you would use it:

var dict = new DefaultDictionary<string, int>();
Debug.WriteLine(dict["foo"]);  // prints "0"
dict["bar"] = 5;
Debug.WriteLine(dict["bar"]);  // prints "5"

Or like this:

var dict = new DefaultDictionary<string, List<int>>();
dict["foo"].Add(1);
dict["foo"].Add(2);
dict["foo"].Add(3);
3

Something to get you started. I basically just changed the this indexer. Since I don't know the complete functionality of python's defaultdict I cannot improve it further. Your given example will work.

public class DefaultDictionary<TKey, TValue> : IDictionary<TKey,TValue>
{
    private readonly Func<TValue> _defaultSelector;
    private readonly Dictionary<TKey, TValue> _values = new Dictionary<TKey, TValue>();

    public DefaultDictionary()
        : this(() => default(TValue))
    {
    }

    public DefaultDictionary(Func<TValue> defaultSelector)
    {
        _defaultSelector = defaultSelector;
    }

    public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
    {
        return _values.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }

    public void Add(KeyValuePair<TKey, TValue> item)
    {
        ((IDictionary<TKey,TValue>)_values).Add(item);
    }

    public void Clear()
    {
        _values.Clear();
    }

    public bool Contains(KeyValuePair<TKey, TValue> item)
    {
        return ((IDictionary<TKey,TValue>)_values).Contains(item);
    }

    public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
    {
        ((IDictionary<TKey, TValue>)_values).CopyTo(array, arrayIndex);
    }

    public bool Remove(KeyValuePair<TKey, TValue> item)
    {
        return ((IDictionary<TKey, TValue>)_values).Remove(item);
    }

    public int Count { get { return _values.Count; } }
    public bool IsReadOnly { get { return ((IDictionary<TKey, TValue>) _values).IsReadOnly; } }
    public bool ContainsKey(TKey key)
    {
        return _values.ContainsKey(key);
    }

    public void Add(TKey key, TValue value)
    {
        _values.Add(key, value);
    }

    public bool Remove(TKey key)
    {
        return _values.Remove(key);
    }

    public bool TryGetValue(TKey key, out TValue value)
    {
        return _values.TryGetValue(key, out value);
    }

    public TValue this[TKey key]
    {
        get
        {
            if (!_values.ContainsKey(key))
            {
                _values.Add(key, _defaultSelector());
            }
            return _values[key];
        }
        set
        {
            if(!_values.ContainsKey(key))
            {
                _values.Add(key, _defaultSelector());
            }
            _values[key] = value;
        }
    }

    public ICollection<TKey> Keys { get { return _values.Keys; } }
    public ICollection<TValue> Values { get { return _values.Values; } }

    public Dictionary<TKey, TValue> ToDictionary()
    {
        return new Dictionary<TKey, TValue>(_values);
    }
}
0

I don't think there is an equivalent, but given your example you could do this with LINQ:

var words = new List<string>{ "One", "Two", "Three", "One" };
var frequencies = words.GroupBy (w => w).ToDictionary (w => w.Key, w => w.Count());

The ConcurrentDictionary (in System.Collections.Generic) behaves very similar (although designed for concurrent use)

  • To retrieve the value: The GetOrAdd method returns the value for a key, and if it doesn't exist, creates one using a value factory.

  • To set the value: The AddOrUpdate method updates a value, or sets it if it doesn't exist yet

Advantages:

  • Thread safe
  • Full control over the default value and the update step

Disadvantages:

  • Slightly more verbose syntax

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Alexander Ross

Alexander Ross

Gaming, Esports & Interactive Media Writer

Alexander Ross has covered the video game industry for a decade, writing deep dives on game design, esports tournaments, VR developments, and gaming culture.

Share this article
Twitter Facebook Pinterest