代码之家  ›  专栏  ›  技术社区  ›  chikak

在字典中自动创建集合<key,collection<value>>

  •  7
  • chikak  · 技术社区  · 16 年前

    很多时候我必须创造一个 Dictionary<KeyType, List<ValueType>>

    在开始使用字典之前,我必须先验证是否已为该键创建了列表。

    //Can i remove these two lines?
    if(!dict.ContainsKey(key)) 
        dict[key]= new List<ValueType>;
    
    //now use the key
    dict[key].Add(value);
    

    我知道它只有“2行”代码,但它让我很恼火,我认为它可以被删除。

    我可以用某种方式扩展字典,但在我做之前,我想知道是否有人找到了一种巧妙的方法来删除上面的内容 if 语句。

    基本上我想创建一个 Dictionary<KeyType, Collection<ValueType>> 立即开始使用,就像 dict[key].Add(value) .

    4 回复  |  直到 16 年前
        1
  •  6
  •   Jon Skeet    16 年前

    您可以创建一些类似谷歌Java集合的东西 Multimap …或者您可以添加这样的扩展方法:

    public static void AddValue<TKey, TValue>
        (this IDictionary<TKey, List<TValue>> dictionary, TKey key, TValue value)
    {
        List<TValue> values;
        if (!dictionary.TryGetValue(key, out values))
        {
            values = new List<TValue>();
            dictionary.Add(key, values);
        }
        values.Add(value);
    }
    

    正如比万所说, Lookup 也可以帮助-但您只能使用 ToLookup 方法,以后不能修改它。在许多情况下,这是一件非常好的事情,但是如果你需要一个可变的地图,那么你将得到类似上面的东西。

        2
  •  2
  •   Bevan    16 年前

    看看 LookUp 用linq在.net 3.5中引入的类-它可能正是您要查找的内容:a Dictionary 类似于每个键支持多个项的类。

    可能唯一显著的缺点是,由于查找是不可变的,所以必须在一个批处理中提供所有元素。

        3
  •  2
  •   Sam Harwell    16 年前

    这个 ConcurrentDictionary<T,K>.GetOrAdd 方法非常有用。

    private ConcurrentDictionary<string, ICollection<int>> _dictionary;
    
    private static ICollection<int> CreateEmptyList(string dummyKey)
    {
        return new List<int>();
    }
    
    private void AddValue(string key, int value)
    {
        ICollection<int> values = _dictionary.GetOrAdd(key, CreateEmptyList);
        values.Add(value);
    }
    

    编辑:下面是一个如何将该特性作为扩展方法实现的示例 IDictionary<T,K> (C(3)):

    注意 IDictionary<TKey, TValue> 通常不是线程安全的,因此如果您希望使用此扩展方法实现线程安全,则必须像对其他操作一样手动实现它。

    public static TValue GetOrAdd<TKey, TValue>(
        this IDictionary<TKey, TValue> dictionary,
        TKey key,
        Func<TKey, TValue> valueFactory)
    {
        TValue value;
        if (!dictionary.TryGetValue(key, out value))
        {
            value = valueFactory(key);
            dictionary.Add(key, value);
        }
    
        return value;
    }
    
        4
  •  1
  •   vgru    16 年前

    要添加到答案中,还可以添加一个更通用的扩展,它接受委托进行实例化:

    public static TValue GetOrCreate<TKey, TValue>
        (this IDictionary<TKey, TValue> dict, 
              TKey key, 
              Func<TKey, TValue> getValue)
    {
        TValue value;
        if (!dict.TryGetValue(key, out value))
        {
            dict.Add(key, getValue(key));
        }
        return value;
    }
    

    然后您可以提供您喜欢的任何实例化方法:

    Dictionary<int, string> dict = new Dictionary<int, string>();
    string result = dict.GetOrCreate(5, i => i.ToString());
    
    推荐文章