tags:

views:

8379

answers:

14

Are there any dictionary classes in the .NET base class library which allow duplicate keys to be used? The only solution I've found is to create, for example, a class like:

Dictionary<string, List<object>>

But this is quite irritating to actually use. In Java, I believe a MultiMap accomplishes this, but cannot find an analog in .NET.

+1  A: 

.NET does not have a class like that (though you could build one or find code for one somewhere I'm sure). The construct you mentioned in your question is a reasonable way to handle it.

Jonathan
+1  A: 

I think something like List<KeyValuePair<object, object>> would do the Job.

MADMap
How do you look something up in that list by it's key?
wizlb
You have to iterate through it: but I was not aware of the LookUp-Class of .NET 3.5: maybe this is more useful for searching in it's content.
MADMap
@wizlib: The only way is to loop through the list, which is not nearly as efficient as hashing. -1
petr k.
+1  A: 

Duplicate keys break the entire contract of the Dictionary. In a dictionary each key is unique and mapped to a single value. If you want to link an object to an arbitrary number of additional objects, the best bet might be something akin to a DataSet (in common parlance a table). Put your keys in one column and your values in the other. This is significantly slower than a dictionary, but that's your tradeoff for losing the ability to hash the key objects.

Ryan
+1  A: 

Do you mean congruent and not an actual duplicate? Otherwise a hashtable wouldn't be able to work.

Congruent means that two separate keys can hash to the equivalent value, but the keys aren't equal.

For example: say your hashtable's hash function was just hashval = key mod 3. Both 1 and 4 map to 1, but are different values. This is where your idea of a list comes into play.

When you need to lookup 1, that value is hashed to 1, the list is traversed until the Key = 1 is found.

If you allowed for duplicate keys to be inserted, you wouldn't be able to differentiate which keys map to which values.

Nicholas Mancuso
A hash table already handles keys which happen to hash to the same value (this is called a collision). I am referring to a situation where you want to map multiple values to the same exact key.
+3  A: 

If you are using strings as both the keys and the values, you can use System.Collections.Specialized.NameValueCollection, which will return an array of string values via the GetValues(string key) method.

Matt
+8  A: 

I just came across the PowerCollections library which includes, among other things, a class called MultiDictionary. This neatly wraps this type of functionality.

A: 

This is the first implementation I was able to find; PowerCollections may have one as well, I've not checked. There isn't one in the base FCL.

technophile
+1  A: 

The NameValueCollection supports multiple string values under one key (which is also a string), but it is the only example I am aware of.

I tend to create constructs similar to the one in your example when I run into situations where I need that sort of functionality.

ckramer
+30  A: 

If you're using .NET 3.5, use the Lookup class.

EDIT: You generally create a Lookup using Enumerable.ToLookup. This does assume that you don't need to change it afterwards - but I typically find that's good enough.

If that doesn't work for you, I don't think there's anything in the framework which will help - and using the dictionary is as good as it gets :(

Jon Skeet
Awesome - I never heard about that. Btw, your book is great.
Nice. I think I have written this type of a collection a couple of times. I was not aware that this came with 3.5.
Jason Jackson
Thanks for the heads-up on Lookup. It offers a great way to partition (group) results from a linq query that aren't standard orderby criteria.
Robert Paulson
It has no constructors and the objects are immutable... so what good is this?
Josh Stodola
@Josh: You use Enumerable.ToLookup to create one.
Jon Skeet
@Jon I ended up using a `List(Of KeyValuePair(Of String, Object))`
Josh Stodola
A: 

Actually I would think your solution would be rather simple to use, a simple lookup gets you a list of items that match that key. What are you trying to do?

WaldenL
It's annoying to add new items to the hash because you have to check if the list exists.
A: 

Have a look at C5's HashBag class.

Yuval
Wow, great library!
I am using it a lot, but I have no idea how many others ...
Tomas Pajonk
+3  A: 

Very important note regarding use of Lookup:

You can create an instance of a Lookup(TKey, TElement) by calling ToLookup on an object that implements IEnumerable(T)

There is no public constructor to create a new instance of a Lookup(TKey, TElement). Additionally, Lookup(TKey, TElement) objects are immutable, that is, you cannot add or remove elements or keys from a Lookup(TKey, TElement) object after it has been created.

(from MSDN)

I'd think this would be a show stopper for most uses.

TheSoftwareJedi
+3  A: 

The List class actually works quite well for key/value collections containing duplicates where you would like to iterate over the collection. Example:

List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();

// add some values to the collection here

for (int i = 0;  i < list.Count;  i++)
{
    Print(list[i].Key, list[i].Value);
}
A: 

In answer to the original question. Something like "Dictionary>" is implemented in a class called MultiMap in The Code Project.

http://www.codeproject.com/KB/cs/MultiKeyDictionary.aspx

Dan