C# Dictionary<T> Tricks

Posted by OmegaMan at October 13, 2008

Category: How To, Linq

Tags: , ,

>(Post Updated 4/2/2011 : Added extra example)

This article demonstrates the Tribal Knowledge of using a Dictionary to do the things that the Swiss Army Knife Hashtable used to do.

For .Net 3 through .Net 4.

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!

Share

15 Comments

  1. Swaroop says

    Hi.

    The article is great.

    Can you please elaborate on how to access dictionary of dictionary?

    Example:

    • I want to retrieve the whole inner dictionary based on the outer dictionary key.
    • I want to retrieve inner dictionary key’s value

    Thanks in advance.

    Cheers !

    Reply
  2. omegaman says

    #1: Continuing with the example in the article to get a reference to the inner dictionary pass in the appropriate key such as:

    Dictionary<int, string> subDictionary = myDicts["Test"];
    
    Console.WriteLine( subDictionary[41] ); // Prints Jabberwocky
    

    #2 With the reference gotten above in #1 its business as usual and no special tricks are needed.

    HTH

    Reply
  3. Swaroop says

    Got it.
    Gr8.
    I was hoping i could access the inner dictionary directly.
    But anyways this worked for me.
    Thanks,

    SWAROOP

    Reply
    • omegaman says

      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?

      Reply
  4. Swaroop says

    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

    Reply
  5. Dru says

    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

    Reply
  6. omegaman says

    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

    Reply
  7. Rick Walker says

    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.

    Reply
  8. omegaman says

    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.

    Reply
  9. swatzzz says

    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!!

    Reply
    • OmegaMan says

      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

      Reply
  10. TheDoomedOne says

    Am below Novice level. That being said, i am not clear on how you populate multiple entries of both levels of the dictionaries.

    Reply
    • OmegaMan says

      I added an extra loading example. HTH

      Reply
  11. BrianT says

    “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

    Reply
    • OmegaMan says

      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.

      Reply

Leave a comment

(required)
(required) (will not be published)

This site uses Akismet to reduce spam. Learn how your comment data is processed.