将元素添加到列表字典

时间:2013-12-16 12:56:15

标签: c# dictionary

我有

Dictionary<string, List<int>> myDict = new Dictionary<string, List<int>>();

并且在某些时候我想为myDict添加特定字典键的数字。

我正在做

if (!myDict.ContainsKey(newKey)){
    myDict[newKey] = new List<int>();
}
myDict[newKey].Add(myNumber);

但这似乎很容易在某些时候忘记ContainsKey检查。 我已经搜索了一种让字典返回新列表的方法,以防myDict [“entry”]不存在,但我找不到任何东西。

6 个答案:

答案 0 :(得分:2)

您可以使用TryGetValue

List<int> list;
if(!myDict.TryGetValue(newKey, out list))
{
    list = new List<int>();
    myDict.Add(newKey, list);
}
list.Add(myNumber);

如果Dictionary是一个字段,我会在一个方法中封装access:

Dictionary<string, List<int>> myDict = new Dictionary<string, List<int>>();

public void AddNumber(string key, int value)
{
     List<int> list;
     if(!myDict.TryGetValue(key, out list))
     {
         list = new List<int>();
         myDict.Add(key, list);
     }
     list.Add(value);
}

答案 1 :(得分:2)

这是我提到的LazyLookup示例的相对简单的实现。它只是出于简洁/简洁而实现IEnumerable来回答这个问题。

基本上,在访问索引时,它将确保它已经初始化为List<T>类的新实例。

public class LazyLookup<TKey, TValue> : IEnumerable<List<TValue>>
{
   private readonly Dictionary<TKey, List<TValue>> CachedEntries;
   private readonly Func<List<TValue>> LazyListCreator;

    public LazyLookup()
        : this(() => new List<TValue>())
    {

    }
    public LazyLookup(Func<List<TValue>> lazyListCreator)
    {
        this.LazyListCreator = lazyListCreator;
        this.CachedEntries = new Dictionary<TKey, List<TValue>>();
    }

    public List<TValue> this[TKey key]
    {
        get
        {
            return GetOrCreateValue(key);
        }
    }

    private List<TValue> GetOrCreateValue(TKey key)
    {
        List<TValue> returnValue;
        if (!CachedEntries.TryGetValue(key, out returnValue))
        {
            returnValue = LazyListCreator();
            CachedEntries[key] = returnValue;
        }
        return returnValue;
    }

    public IEnumerator<List<TValue>> GetEnumerator()
    {
        return CachedEntries.Values.GetEnumerator();
    }

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

有一些用法:

var lazyLookup = new LazyLookup<string, int>();

lazyLookup["nocheck"].Add(9001);

//outputs 9001
Console.WriteLine(lazyLookup["nocheck"][0]);

//outputs 0 as it's a newly initialized list
Console.WriteLine(lazyLookup["someOtherLookup"].Count); 

此时,您可以将其更新为线程安全(因为GetOrCreateValue当前不是线程安全),或者将其概括为一般,因此它不会假设它List<T>任何类型,或者扩展它以实现完整的IDictionary<TKey, TValue>接口。但至少,如果经常使用您发布的上述模式,您可以考虑使用一些封装来直接使用字典,这会使任务变得无足轻重并消除代码重复。

答案 2 :(得分:1)

如果您使用ConcurrentDictionary<T>,则可以执行此操作:

 myDict.GetOrAdd(newKey, new List<int>()).Add(myNumber);

答案 3 :(得分:1)

您实际上可以使用其他人的建议。通过在方法中封装访问,甚至使用ConcurrentDictionary。

但是对我来说,我会有一个自定义字典,所以如果它没有看到元素,你可以实际实现myDict["entry"]所做的事情。

这件事的好处是你可以完全控制你希望这本词典的表现方式。

class MyCustomDictionary<TKey, TValue> : IDictionary<TKey, TValue>
    where TValue : class, new()
{
    private Dictionary<TKey, TValue> _dictionary;

    public MyCustomDictionary()
    {
        _dictionary = new Dictionary<TKey, TValue>();
    }

    public TValue this[TKey key] // this is what's important
    {
        get
        {
            TValue val;
            if (!_dictionary.TryGetValue(key, out val)) // if there is no element for that key, add a new element and return it
            {
                _dictionary.Add(key, new TValue());
                return _dictionary[key];
            }
            else // else return the found element
            {
                return val;
            }
        }
        set
        {
            _dictionary[key] = value;
        }
    }

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

    public bool ContainsKey(TKey key)
    {
        return _dictionary.ContainsKey(key);
    }

    public ICollection<TKey> Keys
    {
        get { return _dictionary.Keys; }
    }

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

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

    public ICollection<TValue> Values
    {
        get { return _dictionary.Values; }
    }

    public void Add(KeyValuePair<TKey, TValue> item)
    {
        _dictionary.Add(item.Key, item.Value);
    }

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

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

    public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
    {
        _dictionary.ToList().CopyTo(array, arrayIndex); // do you need this? you can leave this :)
    }

    public int Count
    {
        get { return _dictionary.Count; }
    }

    public bool IsReadOnly
    {
        get { return false; }
    }

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

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

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return _dictionary.GetEnumerator();
    }
}

然后你就像使用它一样:

MyCustomDictionary<string, List<int>> myCustomDict = new MyCustomDictionary<int, List<int>>();
// return a new List of int
var someElementThatIsNotFound = myCustomDict["keyThatIsNonExistent"];

答案 4 :(得分:0)

您可以使用TryGetValue方法:如果字典中有关键字 你应该只将值添加到列表中;否则你应该 添加一个包含值的列表:

List<int> list

if (myDict.TryGetValue(newKey, out list))
  list.Add(myNumber);
else
  myDict.Add(newKey, new List<int>() { myNumber });

答案 5 :(得分:0)

已经有很多好的答案。我出于这个原因实现了扩展方法:

    public static TVALUE GetOrSet<TKEY, TVALUE>(this IDictionary<TKEY, TVALUE> self,
                                                TKEY key,
                                                Func<TVALUE> defaultValue)
    {
        TVALUE value;
        if (!self.TryGetValue(key, out value))
        {
            value = defaultValue();
            self[key] = value;
        }
        return value;
    }   // eo GetOrSet

请注意,如果值不存在,则需要一个函数来分配值。无论哪种方式,都将返回该值。用法:

var dict = new Dictionary<string, List<int>>();

List<int> ints = dict.GetOrSet("list1", () => return new List<int>());
ints.Add(1);

如果你没有再次引用它,你可能会更简洁:

dict.GetOrSet("list1", () => return new List<int>()).Add(1);