多值字典?

发布于 2024-09-26 02:13:26 字数 185 浏览 4 评论 0 原文

有人知道 MultiValueDictionary 的良好实现吗?基本上,我想要一个允许每个键有多个值的东西。我希望能够执行类似的操作

dict.Add(key, val);

,如果该键尚不存在,它将添加它,如果存在,它只会向该键添加另一个值。我只是要迭代它,所以我并不关心其他检索方法。

Anyone know of a good implementation of a MultiValueDictionary? Basically, I want something that allows multiple values per key. I want to be able to do something like

dict.Add(key, val);

And if the key doesn't already exist, it will add it, if it does, it will just add another value to that key. I'm just going to iterate over it, so I don't really care about the other retrieval methods.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

葬花如无物 2024-10-03 02:13:26

Microsoft 刚刚添加了您正在寻找的正式预发布版本(称为 MultiValueDictionary),可通过 NuGet 获取:https://www.nuget.org/packages/Microsoft.Experimental.Collections/

有关使用信息和更多详细信息可以通过官方 MSDN 博客文章找到这里: http: //blogs.msdn.com/b/dotnet/archive/2014/06/20/would-you-like-a-multidictionary.aspx

我是此包的开发人员,因此请在此处告诉我如果您对性能或任何其他问题有任何疑问,请访问 MSDN。

希望有帮助。

Microsoft just added an official prelease version of exactly what you're looking for (called a MultiValueDictionary) available through NuGet here: https://www.nuget.org/packages/Microsoft.Experimental.Collections/

Info on usage and more details can be found through the official MSDN blog post here: http://blogs.msdn.com/b/dotnet/archive/2014/06/20/would-you-like-a-multidictionary.aspx

I'm the developer for this package, so let me know either here or on MSDN if you have any questions about performance or anything.

Hope that helps.

野味少女 2024-10-03 02:13:26

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

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

}

You can easily make one from a dictionary of lists:

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

}
完美的未来在梦里 2024-10-03 02:13:26

它不存在,但您可以从 Dictionary 和 List 快速构建一个:

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
}

It doesn't exist, but you can build one pretty quickly from Dictionary and List:

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
}
计㈡愣 2024-10-03 02:13:26

您始终可以使用 Tuple 作为第二个通用参数:

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

这将允许您将多个值绑定到单个键。

为了便于使用,您可以创建一个扩展方法来检查密钥是否存在以及列表中的添加内容。

You can always use a Tuple for your second generic parameter:

var dict = new Dictionary<string,Tuple<string,int,object>>();
dict.Add("key", new Tuple<string,int,object>("string1", 4, new Object()));

Or even , a generic List as a second generic parameter:

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

That will allow you to bind multiple values to a single key.

For ease of use, you can create an extension method that will check for existence of a key and addition to the list.

空宴 2024-10-03 02:13:26

这是我不久前写的,你可以使用。

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

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

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

Here's one I wrote a while back that you can use.

It has a "MultiValueDictionary" class that inherits from Dictionary.

It also has an extension class that allows you to use the special Add functionality on any Dictionary where the value type is an IList; that way you're not forced to use the custom class if you don't want to.

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);
    }
}
标点 2024-10-03 02:13:26

只是为了将我的 0.02 美元添加到解决方案集合中:

早在 2011 年,我就有了同样的需求,并创建了一个 MultiDictionary,其中包含所有 .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);

}

它可以在 .NET 2.0 以上的任何版本上进行编译,到目前为止我已将其部署在Xbox 360、Windows Phone 7、Linux 和 Unity 3D。还有一个完整的单元测试套件,涵盖了每一行代码。

该代码根据 Common Public License 获得许可(简而言之:一切都可以,但错误修复库的代码必须发布)并且可以在 我的 Subversion 存储库中找到

Just to add my $0.02 to the collection of solutions:

I had the same need back in 2011 and created a MultiDictionary with a pedantically complete implementation of all the .NET interfaces. That includes enumerators that return a standard KeyValuePair<K, T> and support for the IDictionary<K, T>.Values property providing a collection of actual values (instead of an ICollection<ICollection<T>>).

That way, it fits in neatly with the rest of the .NET collection classes. I also defined an IMultiDictionary<K, T> interface to access operations that are particular to this kind of dictionary:

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

}

It can be compiled on anything from .NET 2.0 upwards and so far I've deployed it on the Xbox 360, Windows Phone 7, Linux and Unity 3D. There's also a complete unit test suite covering every single line of the code.

The code is licensed under the Common Public License (short: anything goes, but bug fixes to the library's code have to published) and can be found in my Subversion repository.

谷夏 2024-10-03 02:13:26

您可以使用 PowerCollections 中的 MultiDictionary 类。

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

You could use MultiDictionary class from PowerCollections.

It returns ICollection{TValue} for the key asked.

遥远的她 2024-10-03 02:13:26

然而这里是我使用ILookup的尝试和一个内部KeyedCollection。确保关键属性是不可变的。
交叉发布于此处

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

Yet here's my attempt using ILookup<TKey, TElement> and an internal KeyedCollection. Make sure the key property is immutable.
Cross posted here.

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; }
  }
}
泅渡 2024-10-03 02:13:26

目前应该这样做...

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

This ought to do for now...

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();
    }
}
怼怹恏 2024-10-03 02:13:26

自定义类型的替代方案可以是通用扩展,它在找不到时添加键和值:

public static V getValue<K, V>(this IDictionary<K, V> d, K key) where V : new() {
    V v; if (!d.TryGetValue(key, out v)) { v = new V(); d.Add(key, v); } return v; } 

示例使用:

var d = new Dictionary<int, LinkedList<int>>();
d.getValue(1).AddLast(2);

Alternative to custom type can be a generic extension that adds key and value when not found:

public static V getValue<K, V>(this IDictionary<K, V> d, K key) where V : new() {
    V v; if (!d.TryGetValue(key, out v)) { v = new V(); d.Add(key, v); } return v; } 

Sample use:

var d = new Dictionary<int, LinkedList<int>>();
d.getValue(1).AddLast(2);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文