有人知道MultiValueDictionary
的良好实施吗?基本上,我想要一些允许每个键有多个值的东西。我希望能够做类似
dict.Add(key, val);
如果密钥尚不存在,它将添加密钥,如果密钥已添加,则只会向该密钥添加另一个值。我只是要迭代它,所以我并不关心其他检索方法。
答案 0 :(得分:34)
微软刚刚在NuGet上添加了一个官方预发布版本,你正在寻找它(称为MultiDictionary):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上告诉我。
希望有所帮助。
答案 1 :(得分:20)
您可以从列表字典轻松制作一个:
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);
}
}
答案 2 :(得分:10)
它不存在,但您可以从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
}
答案 3 :(得分:4)
您始终可以使用Tuple作为第二个通用参数:
var dict = new Dictionary<string,Tuple<string,int,object>>();
dict.Add("key", new Tuple<string,int,object>("string1", 4, new Object()));
甚至,通用List作为第二个通用参数:
var dict = new Dictionary<string,List<myType>>();
这将允许您将多个值绑定到单个键。
为了便于使用,您可以创建一个扩展方法,以检查是否存在密钥并添加到列表中。
答案 4 :(得分:4)
这是我之前写的一篇你可以使用的文章。
它有一个继承自Dictionary的“MultiValueDictionary”类。
它还有一个扩展类,允许您在值类型为IList的任何Dictionary上使用特殊的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);
}
}
答案 5 :(得分:2)
您可以使用PowerCollections中的MultiDictionary类。
它会为要求的密钥返回ICollection {TValue}。
答案 6 :(得分:2)
只需将0.02美元添加到解决方案集合中:
我在2011年遇到了同样的需求并创建了一个MultiDictionary
,其中包含了所有.NET接口的完整实现。这包括返回标准KeyValuePair<K, T>
的枚举数,并支持IDictionary<K, T>.Values
属性,提供实际值的集合(而不是ICollection<ICollection<T>>
)。
这样,它与.NET集合类的其余部分完全吻合。我还定义了一个IMultiDictionary<K, T>
接口来访问特定于这种字典的操作:
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许可的(简称:任何内容,但必须发布对代码库的代码的错误修复),并且可以在my Subversion repository中找到。
答案 7 :(得分:1)
然而here尝试使用ILookup<TKey, TElement>
和内部KeyedCollection
。确保key属性是不可变的
Cross已发布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; }
}
}
答案 8 :(得分:0)
现在应该这样做......
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();
}
}
答案 9 :(得分:0)
自定义类型的替代方法可以是通用扩展,在未找到时添加键和值:
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);