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 somethi
Microsoft just added an official prelease version of exactly what you're looking for (called a MultiDictionary) 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.
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);
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);
}
}
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.
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; }
}
}
You could use MultiDictionary class from PowerCollections.
It returns ICollection{TValue} for the key asked.