So far we’ve had the opportunity to take a deep C# dive on arrays, lists, and the very valuable enum. Today we are going to stay in the System.Collections.Generic namespace and learn about a structure that’s designed for lookups?the C# dictionary.
In this post, we’ll take a look at what the dictionary is, exactly.? Form there, we’ll cover everything you need to know about it, including how to use it and what its methods are.? And, throughout describing these things, we’ll use examples, highlight best practices, and caution you about pitfalls along the way.
C# Dictionary: It Is What?You Think It?Is (Probably)
Most of?us are familiar with the concept of a dictionary, probably. If you want to know the definition of a word, you pull out your dictionary (a large book with words and definitions in it), look up the word alphabetically, and viola, there is the definition and proper spelling of the word!
The same holds true for a thesaurus, encyclopedia, and that dreaded heavy phone book you used to have delivered to your home.? I realize that there is?likely a generation or?two?now that?might not?see the likes of any of these books, so the?reference might be lost on them.
I am thinking about my?elementary and?middle school-aged sons.? When they want the definition of a word, Google is literally a click away.? Better yet, why click when Alexa and Siri are always ready to chime in with an answer!
While the paper versions of these tools might be outdated, the concept behind them is not.
The main idea is that you are using a key to perform a lookup against a data structure.? In the case of the dictionary, the key is the word whose definition you seek.? The data structure is your book of words and definitions, and the lookup for you is an alphabetical search within the book.
The Big Red Dictionary That Used to be on Your Desk Key: the word who's definition you seek Data: big red book of words and definitions Lookup: alphabetical seek
C# has taken this concept and implemented it into the Systems.Collections.Generic namespace with the Dictionary?type.
Dictionary<TKey,?TValue> Class Key: TKey, when declaring this is the "type" of your key. Data: This would be the dictionary data structure itself Lookup: Hash lookup by Key
Using C#, you can create your own data structures that are sortable by a key of your choice.? The key can be of type integer?or string as in our example below, but key type is not limited to any particular type. The values can also be of any type, with a few examples to follow.
A C# Dictionary of a Dictionary?Simple
Here is a simple dictionary object that uses a string as a key and a string as its value.
using System;
using System.Collections.Generic;
public class SimpleDictionary {
public static void Main()
{
Dictionary<string, string> bigRedBook = new Dictionary<string, string>();
//use the Add method to add items to the dictionary
bigRedBook.Add("acorn","the fruit of the oak, a smooth oval nut in a rough cuplike base.");
bigRedBook.Add("adore","love and respect (someone) deeply.");
bigRedBook.Add("available","able to be used or obtained; at someone's disposal.");
}
}
A C# Dictionary of Dictionary?Deeper
To take a deeper dive, this dictionary uses a string as its key and the Definition?object as its value.
class DeeperDictionary { public class Definition { public string Word { get; set; } public string PartOfSpeech { get; set; } public string Meaning { get; set; } } public static void Main() { Dictionary<string, Definition> bigRedBook = new Dictionary<string, Definition>(); var definition1 = new Definition { Word = "acorn", PartOfSpeech = "noun", Meaning = "the fruit of the oak, a smooth oval nut in a rough cuplike base." }; var definition2 = new Definition { Word = "adore", PartOfSpeech = "verb", Meaning = "love and respect (someone) deeply." }; var definition3 = new Definition { Word = "available", PartOfSpeech = "adj", Meaning = "able to be used or obtained; at someone's disposal." }; //use the Add method to add items to the dictionary bigRedBook.Add("acorn", definition1); bigRedBook.Add("adore", definition2); bigRedBook.Add("available", definition3); } }
Best Practice: Throw a try/catch around your Add method.? The Add method will throw an exception if the key is already in the dictionary.
try { bigRedBook.Add("acorn", definition1); } catch (ArugmentException) { Console.WriteLine("An element with Key = \"acorn\" already exists."); }
Just Another Data Structure?
So, hopefully, we’re starting to understand what a dictionary is.
But why would I use it?? Is this just another data structure at my disposal?
This is solid thinking on your part!? Implementing these data structures into a language is not a trivial decision.
Think about all of the work and man hours that went into creating this new type that all of us C# programmers get to use.? But let’s think through why you might use a dictionary over, say, an array or even a list.
The C# dictionary is based on a hashtable.? Hashtables are data structures that are optimized for lookups.
The hashing algorithms are fast and don’t require a full scan of all items to find the keys needed.? Hashtables in C# are not strongly typed like they are in a dictionary, so you are not always assured of what type of data you will have in your hashtable as you would in the C# dictionary. There are some other distinctions between hashtables and dictionaries that we don’t need to address, but you can find out more here.
Best practice: Use a C# dictionary when you have data that you are going to perform lookups on, and where traversing each item would be too costly.
Pitfall: The performance gains from using lookups on a dictionary do not become apparent on very small data sets.? In those cases, a C# list may serve the same purpose.
C# Dictionary Methods & Properties
We’ve spent some time now building a few dictionaries (using the Add method), and we have also spent time discussing some use cases.? Now we’ll take a look under the covers at some of the methods and properties that the dictionary provides.
Properties
Sticking with our example from above of the bigRedBook dictionary, here are some of the important properties (Count, Keys, Values, & Indexer) of the dictionary.
//Count - Get the number of indexed elements in a dictionary var wordCount = bigRedBook.Count; //Keys - Obtain all of the keys in a dictionary List keyList = new List(bigRedBook.Keys); //Values - Obtain all of the item values in a dictionary List itemList = new List(bigRedBook.Values); //Indexer - Obtain the value assigned to a particular key Definition defAdore = bigRedBook["adore"];
Pitfall: The indexer will throw an exception if the key does not exist. Use some of the methods below to ensure the key exists, and/or catch the KeyNotFoundException.
Methods
The Add method was covered in our initial examples, so here are some other key methods that a dictionary provides.
Clear()?removes all keys and values from the dictionary.
bigRedBook.Clear();
ContainsKey()?determines whether the dictionary contains the specified key.
if(! bigRedBook.ContainsKey("adore") ) //ContainsKey returns a Boolean { bigRedBook.Add("adore", definition2); }
Best Practice: Use ContainsKey before adding new elements to your dictionary.
ContainsValue()?determines whether the dictionary contains the specific value.
if (! bigRedBook.ContainsValue(definition2) ) { Console.WriteLine("The value exists in the Dictionary"); }
Pitfall: The ContainsValue method will loop through all elements in the dictionary so use this cautiously.
Remove() (with overload)?removes the value with the specified key from the dictionary.
bigRedBook.Remove("adore"); //Will remove the specified key and value bigRedBook.Remove("adore",definition2); //Overloaded method - Will remove the key and value on exact math
Pitfall: If the key does not exist, or the key/value pair in the overloaded method does not exist, no exception is thrown.
TryAdd()?adds the specified element to the dictionary if the element does not exist. Returns Boolean.
var success = bigRedBook.TryAdd("acorn", definition1); //success returns true if added, false if ignored, no exceptions is thrown if the element exists
TryGetValue()?gets the value of the specified key, if it exists.
Dictionary<string, string> bigRedBook = new Dictionary<string, string>(); bigRedBook.Add("acorn", "the fruit of the oak, a smooth oval nut in a rough cuplike base."); string value = ""; if(bigRedBook.TryGetValue("acorn", out value) { Console.WriteLine("For key acorn, found value {0}", value); }
Best Practice:?Use methods like TryAdd, TryGetValue, and ContainsKey to ensure successful execution of your program.
Iterating & Sorting
The C# dictionary is a data structure, so how do we sort it or iterate over it?? Does it make sense to sort the dictionary if its primary purpose is for lookups?
Sort
Unfortunately, there is no way to sort a C# dictionary.? The order of values added to the dictionary persists until the object is destroyed or the elements removed.
It is worth noting that a list of the keys could be created (the Keys property) and then sorted as a list.? Once you have that list, you iterate over it to obtain the necessary values.
//Get all of the keys in the dictionary List keyList = new List(bigRedBook.Keys); keyList.Sort();
Iterate
There are a couple approaches available in order to iterate over a dictionary.? Consider a new dictionary item that contained a list of foods and the number (int) of calories in each.? We want to find the sum of all the calories in our food dictionary by iterating over the dictionary and adding each value.
int totalCals = 0; Dictionary<string, int> menuItems = new Dictionary<string, int>(); menuItems.TryAdd("hamburger",354); menuItems.TryAdd("hot dog", 151); menuItems.TryAdd("pizza", 285); menuItems.TryAdd("soda", 150); menuItems.TryAdd("ice cream", 137); foreach(var food in menuItems) { totalCals += food.Value; } Console.WriteLine("The total calories in menuItems is {0}", totalCals); // 1077
The foreach loop provides us with a very simple way of iterating over our collection, totaling up the number of calories in our dictionary.? Below is another way to consider iterating over a dictionary.
int totalCals = 0; Dictionary<string, int> menuItems = new Dictionary<string, int>(); menuItems.TryAdd("hamburger",354); menuItems.TryAdd("hot dog", 151); menuItems.TryAdd("pizza", 285); menuItems.TryAdd("soda", 150); menuItems.TryAdd("ice cream", 137); foreach(var food in menuItems.Keys) { totalCals += menuItems[food]; } Console.WriteLine("The total calories in menuItems is {0}", totalCals); // 1077
In this second example, iteration is done through the Keys property, rather than iterating over the collection itself.
The concern, though, is that we have to use the indexer to grab the value at each spot in the collection.? Since we need the value at each location, this method is less efficient.
There might be a use case where this makes sense, perhaps one where every value in the collection is not needed, but be wary of the performance of very large collections using this approach.
Pitfall:?The indexer requires a second lookup, which, when working with large collections, will compound the amount of time it takes to complete.
Wrapping Up
Lookups, lookups, lookups.? We now know the design intentions of the C# dictionary.
We looked at why it’s useful over other data structures, and we examined its properties and methods. The interwebs are full of great articles and discussions about dictionaries, so I encourage you to keep learning more.? Try the samples above, extend them, and keep thinking about ways to use this very fast data structure.
Keep on coding!
You might also be interested in further reading about other C# language concepts:
Learn more how CodeIt.Right can help you automate code reviews and improve the quality of your code.
7 Comments. Leave new
Since using the index operator[] with an unknown key throws and exception, one is almost forced to us TryGetValue() for accessing all values in a Dictionary<>.
This is why, for places where I need a string-to-string Dictionary, I like using an old school StringDictionary (in System.Collections.Specialized). If given an unknown key, the Index operator returns null, which is much easier to deal with. (And it’s even in .NET Core 2.0!)
Great article, thank you.
[…] I worked through a tutorial covering how to use dictionaries in C#. I have worked with?dictionaries before, but they have always been added in by someone else or a […]
[…] Dictionary: Definition, Examples, Best Practices, and Pitfalls. […]
Great article, thank you.
First of all, thanks for the detailed article. Also worth mentioning is its value when dealing with dynamic json strings returned by a REST request.
I.E. var json = new JsonDeserializer().Deserialize<Dictionary<string, string>>(response);
Please notify me if you found any performance conserns while using Dictionary vs hardcoding json objects.
Cheers!
Great article, thank you.