2013-03-25 5 views
5

Есть ли .NET-аналог Python's defaultdict? Мне удобно писать короткий код, например. Подсчет частоты:Аналог параметра defaultdict Python?

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

Так в идеале в C# я мог бы написать:

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

Что означает 'defaultdict' сделать ? Я не знаком с python. Изменить: это просто словарь, который имеет значение по умолчанию для ключей. Вы можете подклассифицировать «Словарь» и реализовать функциональность. – Romoku

+1

Ответ Джона Скита может помочь: http://stackoverflow.com/a/2601501/1786606. – Vladimir

ответ

4

Я не думаю, что есть эквивалент, но, учитывая ваш пример вы могли бы сделать это с помощью LINQ:

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

Что-то, чтобы вы начали. Я в основном просто изменил индексатор this. Поскольку я не знаю полной функциональности python defaultdict, я не могу ее улучшить. Ваш пример будет работать.

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

Вот простая реализация:

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

И как вы будете использовать его:

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

Или так:

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