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