C# 多值词典?

C# 多值词典?,c#,collections,dictionary,C#,Collections,Dictionary,有谁知道一个好的多值字典的实现吗?基本上,我想要的是允许每个键有多个值的东西。我想做一些像这样的事情 dict.Add(key, val); 如果该键不存在,它将添加它,如果它存在,它将只向该键添加另一个值。我只想对它进行迭代,因此我并不真正关心其他检索方法。您可以始终使用a作为第二个泛型参数: var dict = new Dictionary<string,Tuple<string,int,object>>(); dict.Add("key", new Tuple&

有谁知道一个好的
多值字典的实现吗?基本上,我想要的是允许每个键有多个值的东西。我想做一些像这样的事情

dict.Add(key, val);
如果该键不存在,它将添加它,如果它存在,它将只向该键添加另一个值。我只想对它进行迭代,因此我并不真正关心其他检索方法。

您可以始终使用a作为第二个泛型参数:

var dict = new Dictionary<string,Tuple<string,int,object>>();
dict.Add("key", new Tuple<string,int,object>("string1", 4, new Object()));
var dict = new Dictionary<string,List<myType>>();
var dict=newdictionary();
dict.Add(“key”,新元组(“string1”,4,新对象());
或者甚至可以将泛型列表作为第二个泛型参数:

var dict = new Dictionary<string,Tuple<string,int,object>>();
dict.Add("key", new Tuple<string,int,object>("string1", 4, new Object()));
var dict = new Dictionary<string,List<myType>>();
var dict=newdictionary();
这将允许您将多个值绑定到单个键


为便于使用,您可以创建一个扩展方法,该方法将检查是否存在键并添加到列表中。

您可以轻松地从列表字典中创建一个扩展方法:

public class MultiValueDictionary<Key, Value> : Dictionary<Key, List<Value>> {

  public void Add(Key key, Value value) {
    List<Value> values;
    if (!this.TryGetValue(key, out values)) {
      values = new List<Value>();
      this.Add(key, values);
    }
    values.Add(value);
  }

}
公共类多值字典:字典{
公共无效添加(键、值){
列表值;
如果(!this.TryGetValue(键,输出值)){
值=新列表();
添加(键、值);
}
增加(价值);
}
}

这是我不久前写的一个,您可以使用

它有一个从Dictionary继承的“MultiValueDictionary”类

它还有一个扩展类,允许您在值类型为IList的任何字典上使用特殊的Add功能;这样,如果您不想使用自定义类,就不会被迫使用自定义类

public class MultiValueDictionary<KeyType, ValueType> : Dictionary<KeyType, List<ValueType>>
{
    /// <summary>
    /// Hide the regular Dictionary Add method
    /// </summary>
    new private void Add(KeyType key, List<ValueType> value)
    {            
        base.Add(key, value);
    }

    /// <summary>
    /// Adds the specified value to the multi value dictionary.
    /// </summary>
    /// <param name="key">The key of the element to add.</param>
    /// <param name="value">The value of the element to add. The value can be null for reference types.</param>
    public void Add(KeyType key, ValueType value)
    {
        //add the value to the dictionary under the key
        MultiValueDictionaryExtensions.Add(this, key, value);
    }
}

public static class MultiValueDictionaryExtensions
{
    /// <summary>
    /// Adds the specified value to the multi value dictionary.
    /// </summary>
    /// <param name="key">The key of the element to add.</param>
    /// <param name="value">The value of the element to add. The value can be null for reference types.</param>
    public static void Add<KeyType, ListType, ValueType>(this Dictionary<KeyType, ListType> thisDictionary, 
                                                         KeyType key, ValueType value)
    where ListType : IList<ValueType>, new()
    {
        //if the dictionary doesn't contain the key, make a new list under the key
        if (!thisDictionary.ContainsKey(key))
        {
            thisDictionary.Add(key, new ListType());
        }

        //add the value to the list at the key index
        thisDictionary[key].Add(value);
    }
}
公共类多值字典:字典
{
/// 
///隐藏常规字典添加方法
/// 
新的私有void Add(键类型键,列表值)
{            
添加(键、值);
}
/// 
///将指定的值添加到多值字典。
/// 
///要添加的元素的键。
///要添加的元素的值。对于引用类型,该值可以为null。
public void Add(键类型键、值类型值)
{
//将值添加到键下的字典中
多值字典扩展.Add(this,key,value);
}
}
公共静态类多值字典扩展
{
/// 
///将指定的值添加到多值字典。
/// 
///要添加的元素的键。
///要添加的元素的值。对于引用类型,该值可以为null。
public static void Add(此字典),
键类型键,值类型值)
其中ListType:IList,new()
{
//如果字典不包含该键,请在该键下创建一个新列表
如果(!thisDictionary.ContainsKey(键))
{
Add(key,newlistType());
}
//将值添加到索引键处的列表中
此字典[键]。添加(值);
}
}

它不存在,但您可以通过字典和列表快速构建一个:

class MultiDict<TKey, TValue>  // no (collection) base class
{
   private Dictionary<TKey, List<TValue>> _data =  new Dictionary<TKey,List<TValue>>();

   public void Add(TKey k, TValue v)
   {
      // can be a optimized a little with TryGetValue, this is for clarity
      if (_data.ContainsKey(k))
         _data[k].Add(v)
      else
        _data.Add(k, new List<TValue>() { v}) ;
   }

   // more members
}
class MultiDict//no(集合)基类
{
专用字典_data=新字典();
公共无效添加(tk键,tv值)
{
//可以用TryGetValue稍微优化一下,这是为了清晰
如果(_data.ContainsKey(k))
_数据[k]。添加(v)
其他的
_Add(k,newlist(){v});
}
//更多成员
}

现在应该这样做

public class MultiValueDictionary<TKey, TValue> : IEnumerable<KeyValuePair<TKey, TValue>>
{
    private Dictionary<TKey, LinkedList<TValue>> _dict = new Dictionary<TKey, LinkedList<TValue>>();

    public void Add(TKey key, TValue value)
    {
        if(!_dict.ContainsKey(key)) _dict[key] = new LinkedList<TValue>();
        _dict[key].AddLast(value);
    }

    public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
    {
        foreach (var list in _dict)
            foreach (var value in list.Value)
                yield return new KeyValuePair<TKey, TValue>(list.Key, value);
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}
公共类多值字典:IEnumerable
{
专用词典_dict=新词典();
公共无效添加(TKey键,TValue值)
{
如果(!_dict.ContainsKey(key))_dict[key]=newlinkedlist();
_dict[key].AddLast(值);
}
公共IEnumerator GetEnumerator()
{
foreach(目录中的var列表)
foreach(list.value中的var值)
返回新的KeyValuePair(list.Key,value);
}
IEnumerator IEnumerable.GetEnumerator()
{
返回GetEnumerator();
}
}

您可以从中使用多字典类


它返回所请求密钥的ICollection{TValue}。

Microsoft刚刚添加了一个正式的PreRelease版本,该版本正是您要查找的内容(称为MultiDictionary),可通过NuGet访问:

有关用法的信息和更多详细信息,请访问MSDN官方博客:

我是这个软件包的开发人员,如果您对性能或其他方面有任何疑问,请在这里或MSDN上告诉我


希望能有所帮助。

只需将我的$0.02添加到解决方案集合中:

我在2011年也有同样的需求,并创建了一个
多字典
,其中包含了所有.NET接口的学究式完整实现。这包括返回标准
KeyValuePair
的枚举数,以及对提供实际值集合的
IDictionary.Values
属性的支持(而不是
ICollection

这样,它就可以与其他.NET集合类完美地结合在一起。我还定义了一个
IMultiDictionary
接口来访问这种字典特有的操作:

public interface IMultiDictionary<TKey, TValue> :
  IDictionary<TKey, ICollection<TValue>>,
  IDictionary,
  ICollection<KeyValuePair<TKey, TValue>>,
  IEnumerable<KeyValuePair<TKey, TValue>>,
  IEnumerable {

  /// <summary>Adds a value into the dictionary</summary>
  /// <param name="key">Key the value will be stored under</param>
  /// <param name="value">Value that will be stored under the key</param>
  void Add(TKey key, TValue value);

  /// <summary>Determines the number of values stored under a key</summary>
  /// <param name="key">Key whose values will be counted</param>
  /// <returns>The number of values stored under the specified key</returns>
  int CountValues(TKey key);

  /// <summary>
  ///   Removes the item with the specified key and value from the dictionary
  /// </summary>
  /// <param name="key">Key of the item that will be removed</param>
  /// <param name="value">Value of the item that will be removed</param>
  /// <returns>True if the item was found and removed</returns>
  bool Remove(TKey key, TValue value);

  /// <summary>Removes all items of a key from the dictionary</summary>
  /// <param name="key">Key of the items that will be removed</param>
  /// <returns>The number of items that have been removed</returns>
  int RemoveKey(TKey key);

}
公共接口IMultiDictionary:
词典,
词典,
I收集,
我数不清,
数不清{
///将值添加到字典中
///该值将存储在
///将存储在键下的值
无效添加(TKey键、TValue值);
///确定键下存储的值的数量
///将对其值进行计数的键
///存储在指定键下的值的数目
int CountValues(TKey);
/// 
///从字典中删除具有指定键和值的项
/// 
///要删除的项的键
///要删除的项的值
///如果找到并删除了该项,则为True
bool Remove(TKey键、TValue值);
///从字典中删除键的所有项
///要删除的项目的键
///已删除的项目数
内部移除键(TK
public class Lookup<TKey, TElement> : Collection<TElement>, ILookup<TKey, TElement>
{
  public Lookup(Func<TElement, TKey> keyForItem)
    : base((IList<TElement>)new Collection(keyForItem))
  {
  }

  new Collection Items => (Collection)base.Items;

  public IEnumerable<TElement> this[TKey key] => Items[key];
  public bool Contains(TKey key) => Items.Contains(key);
  IEnumerator<IGrouping<TKey, TElement>>
    IEnumerable<IGrouping<TKey, TElement>>.GetEnumerator() => Items.GetEnumerator();

  class Collection : KeyedCollection<TKey, Grouping>
  {
    Func<TElement, TKey> KeyForItem { get; }      
    public Collection(Func<TElement, TKey> keyForItem) => KeyForItem = keyForItem;
    protected override TKey GetKeyForItem(Grouping item) => item.Key;

    public void Add(TElement item)
    {
      var key = KeyForItem(item);
      if (Dictionary != null && Dictionary.TryGetValue(key, out var collection))
        collection.Add(item);
      else
        Add(new Grouping(key) { item });
    }

    public bool Remove(TElement item)
    {
      var key = KeyForItem(item);
      if (Dictionary != null && Dictionary.TryGetValue(key, out var collection)
        && collection.Remove(item))
      {
        if (collection.Count == 0)
          Remove(key);
        return true;
      }
      return false;
    }

  }
  class Grouping : Collection<TElement>, IGrouping<TKey, TElement>
  {
    public Grouping(TKey key) => Key = key;
    public TKey Key { get; }
  }
}