views:

127

answers:

5

Anyone know of a good implementation of a MultiValueDictionary? Basically, I want 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.

+3  A: 

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.

Oded
Yeah, but then I have to check if the key exists before adding to it every time. I want the collection class to handle that automatically.
Mark
You can inherit from Dictionary, overriding `add` to do this check. It is not resource intensive, as checking for a key is pretty quick. Don't optimize before you _need_ to.
Oded
No one said anything about optimization, this is just about convenience. And if I inherit from dictionary, I'm pretty sure I would have to `new` the `Add` method, not `override` which I generally don't like to do because it breaks inheritance. Also, the method signatures need to be slightly different, because some them should actually return lists of TValues, rather than just a TValue. Lastly, I'm not really sure why you've suggested a Tuple.. those aren't expandable?
Mark
@Mark - You say "multiple values for key". It wasn't clear that the values need to be expandable. See my update, regarding the second generic type being a `List`.
Oded
@Oded: That's why I wrote the paragraph below ;) "it will just add another value to that key" re: update: An extension method is a clever solution... I wanted the enumerator to return KeyValuePairs though, not Key,List<Value> pairs though.
Mark
PS: Downvote wasn't me.
Mark
@Mark - you can always use a `Dictionary` as your generic parameter, instead of a `List` (`Dictionary<string,Dictionary<key,value>>`), as a Dictionary is in essence a set of KVPs.
Oded
@Oded: Well that just... no, that rubs me the wrong way :P
Mark
@Mark - I've seen `List<List<List<>>>` in the past... Not pretty, but did the job.
Oded
+5  A: 

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

}
Guffa
+2  A: 

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);
    }
}
DoctaJonez
Of course... inherit from a dict with a list instead! Clever. What's that `new()` bit do? Don't think I've seen that before.
Mark
Taken from MSDN; Use the new modifier to explicitly hide a member inherited from a base class. To hide an inherited member, declare it in the derived class using the same name, and modify it with the new modifier.
DoctaJonez
@DoctaJonez - I believe is he asking about the generic parameter constraint (the only `new()` in the code). @Mark - it is a [generic parameter constraint](http://msdn.microsoft.com/en-us/library/d5x73970.aspx) requiring the passed in generic type to have a public parameterless constructor.
Oded
@Oded: Ah of course, doh!
DoctaJonez
@DoctaJonez: I think @Mark means your `where ListType : new()` constraint. (@Mark: That means `ListType` must have a public parameterless constructor. Also, I'm surprised you would like this answer which hides the `base.Add` method as it seems you disliked that very aspect of Oded's answer.)
Dan Tao
@Dan: Yes.. I noticed my hypocritcalness too. I still don't love it, but at least in this case he made it private and added a 2nd method with a different signature... which still doesn't fix the inheritance problem, but... I dunno! I'm trying to find the lesser of evils. @Oded: Yes, that's what I was referring too. Thanks!
Mark
@Mark: Go with Henk's answer. It isn't evil at all ;)
Dan Tao
+2  A: 

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;

   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
}
Henk Holterman
Lists don't have very efficient inserts, do they? Don't they use an array internally?
Mark
Yes they use an array, and sometimes a List.Add() will need to re-allocate. But mostly Add is O(1).
Henk Holterman
@Mark: `List<T>.Add` has [amortized](http://en.wikipedia.org/wiki/Amortized) O(1) performance, and is generally *faster* than `LinkedList<T>.AddLast` because it requires fewer operations. `LinkedList<T>.AddLast` might make sense if you want to *never* have an O(n) resize happen (even though it will happen rarely on a `List<T>` that you're only adding to).
Dan Tao
@Dan: Ah.. so you're saying the "constant" times in the LinkedList generally outweigh the performance of a List?
Mark
@Mark: Yes. I've seldom seen cases where it made sense to choose a `LinkedList<T>` over a `List<T>` when you're never inserting/removing from the middle (that's where `LinkedList<T>` really shines). When you're just adding to the *end*, `LinkedList<T>` is just costing you a lot more (e.g., creation of `LinkedListNode<T>` objects => more fields to initialize => elimination of arrays' performance advantage due to extremely optimized memory access) for very little benefit: one `LinkedList<T>.AddLast` in a blue moon will outperform a single `List<T>.Add`. The rest will be the opposite.
Dan Tao
@Dan: Good to know. I'll stop using LinkedList then :)
Mark
A: 

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();
    }
}
Mark
Why the (awkward) LinkedList?
Henk Holterman
I agree with this and Henk's ideas. Personally I don't like the idea of inheriting from `Dictionary<TKey, List<TValue>>` (or similar) as I think it exposes too much (calling code could add/remove from the `List<T>` value directly, for example).
Dan Tao
@Henk: Because I thought it would be more efficient than a `List` (see discussion under your answer). @Dan: Yeah... I was going to implement `IDictionary` instead, but even that.. some of the methods don't make sense.
Mark
Yes, I saw the discussion. I thought as much, the mere presence of LinkedList can be a bit misleading. It is used rarely.
Henk Holterman