C# Dictionary<T> Tricks
>(Post Updated 4/2/2011 : Added extra example)
I love the generic Dictionary collection so much, I think that Microsoft might charge me usage on it. Here I present some of the things that I have learned which I call the tribal knowledge of the class.
The first use of the Dictionary was found in .Net 1 HashTable class. That class is a dictionary for storing lists with keys and has the ubiquitously Key Value Pair. With .Net 2 the generic class Dictionary was used, less upfront functionality, but same concepts; data in key value pairs.
While the old hash table could be sorted the dictionary cannot. So how does one sort? The Dictionary is just two lists under the covers. One is for keys and one is for values. Operations don’t go to the hash table but to the lists. Once you remember that and understand it, the obtuseness of the Dictionary goes away…
Sorting
Ok, so we can sort…but one complaint or question found in the MSDN forums that I have run into is that, the Hashtable could be sorted because it exposed IComparer and its cousin the Dictionary does not! How does one get around that?
As mentioned one must think of what a dictionary really is…just two lists. There are two properties exposed on the Dictionary and those are the Keys and Values. Those are shown to the world as ValueCollection and that my friends is the entry pass into the club. One of the interfaces that is exposed is the ValueCollection and it adheres to the ICollection. Bingo! With that we can do sorting! Here is the code snippet:
Dictionary<int, string> myDict = new Dictionary<int, string>() { { 2, "This" }, { 1, "is" }, { 5, "radio" }, { 12, "clash" }, }; List<string> song = new List<string>( myDict.Values ); song.Sort(); // This writes out: "clash is radio This" Console.WriteLine( string.Join( " ", song.ToArray() ) );
We simply use the sorting which is found on the List<T>.
Enumerating over a Dictionary
Sometimes the need is there to run through a dictionary and show the keys and values. When enumerating over a Dictionary it returns a Key Value Pair object. That object holds the key and the value.
Dictionary<string, string> ColumnValuesHash = new Dictionary<string, string>() // ... load with values... foreach (KeyValuePair entry in ColumnValuesHash) Console.WriteLine("{0}: {1}", entry.Key, entry.Value);
Dictionary of Dictionaries
I have used this gem many times. Create a top level dictionary that will hold other dictionaries…its not as bad as it sounds.
Dictionary<int, string> myStringHash = new Dictionary<int, string>(); myStringHash.Add(41, "Jabberwocky"); myStringHash.Add(8675309, "Jenny"); Dictionary< string, Dictionary<int, string>> myDicts = new Dictionary<string, Dictionary<int, string>>(); myDicts.Add("Test", myStringHash); Console.WriteLine( myDicts["Test"][8675309] ); // Prints Jenny
Notice how easy it is to drill down via indexes off of each dictionary.
Dictionary Meets Linq and Gets Sorted
Here is how you can access the dictionary, sort it and enumerate it all in Linq. We will take our above example and do it
Dictionary<int, string> myDict = new Dictionary<int, string>() { { 2, "This" }, { 1, "is" }, { 5, "radio" }, { 12, "clash" }, }; var sorted = from item in myDict orderby item.Value ascending select item.Value; // This writes out: "clash is radio This" Console.WriteLine( string.Join( " ", sorted.ToArray() ) );
Extra Example (Loading on the fly and Linq extension Select Many)
Dictionary<string, Dictionary<int, string>> TopLevel = new Dictionary<string, Dictionary<int, string>>() { { "Dictionary 1", new Dictionary<int, string>() { // Sub "dictionary 1" contains two objects {41, "The Meaning of Life" }, {90125, "Owner of a Lonely Heart"} } }, { "Dictionary 2", new Dictionary<int, string>() { // Sub "Dictionary 2" contains one object {8675309, "Jenny!" } } } }; Console.WriteLine(TopLevel["Dictionary 1"][41]); // Prints out "The Meaning of Life!" // Console.WriteLine(TopLevel["Dictionary 1"][8675309]); // Fails and would throw an exception! That is in Dictionary 2! // Use selectmany to grab all sub objects // (which are a Key value pair of KVP<string, Dictionary<int, string>) // and return the value (the sub dictionaries) and combine // all the those dictionaries from both sub dictionary into one IEnumerable KVP. TopLevel.SelectMany( dict => dict.Value ) // Gets all the DIctionary<int, string> pairs between both dictionaries .ToList() // Convert from IEnumerable to list so we can do the for each below .ForEach( kvp => Console.WriteLine( "{0} is {1}", kvp.Key, kvp.Value ) ); // Outputs the lowest dictionaries. /* above outputs 41 is The Meaning of Life 90125 is Owner of a Lonely Heart 8675309 is Jenny! */
Hope this helps!
Hi.
The article is great.
Can you please elaborate on how to access dictionary of dictionary?
Example:
Thanks in advance.
Cheers !
#1: Continuing with the example in the article to get a reference to the inner dictionary pass in the appropriate key such as:
#2 With the reference gotten above in #1 its business as usual and no special tricks are needed.
HTH
Got it.
Gr8.
I was hoping i could access the inner dictionary directly.
But anyways this worked for me.
Thanks,
SWAROOP
You can access the inner dictionary directly via indexing such as shown in the example
myDicts[“Test”][8675309]
Where it says open top level dictionary “Test” and access its hash item 8675309. Or am I missing what you mean?
Yeah,,u r right. Looks like inner dictionary can be accessed by myDicts[“Test”][8675309]…but it wont retreve me the whole inner dictionary…and even if i point to only myDicts[“Test”], i have to collect the whole inner dictionary into something…which should be a dictionary again or a list or array. Among the three choices, collection again in the dictionary seems to be an easy option..so its fine..i did it fine.
Thanks mate.
Good job!
Cheers.
SWAROOP
Hi, I have a query regarding searching for a key in a dictionary of dictionaries? Is there a way how I can check whether a key is present in any of the dictionaries…and if yes, get the path to that word?
thanks in advance,
Dru
Hi Dru, you will need to create a manager, or maybe an extension method with the smarts to drill down into your dictionaries to provide that information. HTH
I’m trying to tweak the Dictionary<string,Dictionary> to create a Dictionary<string,List> similar to a perl hash array. I’m also trying to fill the Dictionary in an object constructor, one item at at time (static Dictionary), so the List does not exist as a stand alone entity; I just want to add to the appropriate List based on the string. Your example seems to indicate the persistence of the inner Dictionary, so I’m not sure how to tweak your example.
I am not getting your mention of persistence per-se. Describe the problem in more detail on MSDNs C# forum and return the link here, (if I dont’ catch it). Maybe we can help you if you haven’t figured it out already.
I have a Dictionary which stores
The linenum is totally random….so…traversing backwards in the Dictionary collection is impossible using linenum as index.
I thought of using Dictionary within a Dictioanry.
a) Is this approach reasonable, or any other solution ?
b) so, my new struct is…
original_Dict -> (linenum,obj)
ParentDict-> (indexforObj, original_Dict)
using index–, or index++ i can traverse between my original_Dict…however,
how can i find the inner dictionaries KEY value in order to access the inner dictionaries Object!!
You know a dictionary to store line numbers with data seems like overkill. You might be better served by using a Linked List instead and having references to the end and middle. Then its just the cost of traversing to the correct number. That way the list is the same size as the nodes inserted. HTH
Am below Novice level. That being said, i am not clear on how you populate multiple entries of both levels of the dictionaries.
I added an extra loading example. HTH
“Note my blog is sucking up the less than and greater than symbol ”
Use “ampersand symbol” followed by “lt;” for less than and
“ampersand symbol” followed by “gt;” for greater than
Hi Brian, Thanks for pointing out the work around on the comment I did above. (He quoted a section which is now gone) I updated the blog engine since that comment was written and didn’t have SyntaxHighlighter available at the time. I added comment into syntaxhighlighter pre nodes and escaped the less than and greater than with < and > respectfully. Thanks for pointing it out and its nice to get it working.