Home
Map
Dictionary ExamplesPerform fast lookups with string keys. Add elements to Dictionary from System.Collections.Generic.
C#
This page was last reviewed on Nov 10, 2023.
Dictionary. The C# Dictionary is a collection that we can use to map keys to values. Each key must have the same type (like string), and all values must have a type as well.
Shows a dictionaryShows a dictionaryShows a keyvaluepairShows a dictionaryShows a dictionary
For remembering things, the Dictionary is both fast and effective. We specify the key and value types. The Add method inserts into the Dictionary.
ToDictionary
Map
First example. Here we add 4 keys (each with an int value) to 2 separate Dictionary instances. Every Dictionary has pairs of keys and values.
Detail Dictionary is used with different elements. We specify its key type and its value type (string, int).
Version 1 We use Add() to set 4 keys to 4 values in a Dictionary. Then we access the Count property to see how many items we added.
Version 2 This creates a Dictionary with the same internal values as the first version, but its syntax is more graceful.
Shows a dictionary
using System; using System.Collections.Generic; // Version 1: create a Dictionary, then add 4 pairs to it. var dictionary = new Dictionary<string, int>(); dictionary.Add("cat", 2); dictionary.Add("dog", 1); dictionary.Add("llama", 0); dictionary.Add("iguana", -1); // The dictionary has 4 pairs. Console.WriteLine("DICTIONARY 1: " + dictionary.Count); // Version 2: create a Dictionary with an initializer. var dictionary2 = new Dictionary<string, int>() { {"cat", 2}, {"dog", 1}, {"llama", 0}, {"iguana", -1} }; // This dictionary has 4 pairs too. Console.WriteLine("DICTIONARY 2: " + dictionary2.Count);
DICTIONARY 1: 4 DICTIONARY 2: 4
TryGetValue. This is often the most efficient lookup method. In my experience, most of the time we want to use TryGetValue—so learn how to use it right away when learning Dictionary.
Dictionary TryGetValue
Part 1 We invoke TryGetValue, which tests for the key. It then returns the value if it finds the key.
Part 2 Do another look up with TryGetValue. Declare the local variable inside the if-condition.
Shows a dictionary
using System; using System.Collections.Generic; var values = new Dictionary<string, string>(); values.Add("A", "uppercase letter A"); values.Add("c", "lowercase letter C"); // Part 1: local variable result. string result; if (values.TryGetValue("c", out result)) { Console.WriteLine(result); } // Part 2: use inline "out string." if (values.TryGetValue("c", out string description)) { Console.WriteLine(description); }
lowercase letter C lowercase letter C
Foreach. Let us loop over the data in a Dictionary. With each KeyValuePair, there are Key and Value properties—this gives us all data stored.
foreach
Part 1 The code creates a Dictionary with string keys and int values. The Dictionary stores animal counts.
Part 2 In this foreach-loop, each KeyValuePair struct has 2 members, a string Key and an int Value.
KeyValuePair
Part 3 Instead of specifying KeyValuePair directly, often we can just use var for simpler code.
var
Shows a keyvaluepair
using System; using System.Collections.Generic; // Part 1: initialize data. Dictionary<string, int> data = new Dictionary<string, int>() { {"cat", 2}, {"dog", 1}, {"llama", 0}, {"iguana", -1} }; // Part 2: loop over pairs with foreach. foreach (KeyValuePair<string, int> pair in data) { Console.WriteLine("FOREACH KEYVALUEPAIR: {0}, {1}", pair.Key, pair.Value); } // Part 3: use var keyword to enumerate Dictionary. foreach (var pair in data) { Console.WriteLine("FOREACH VAR: {0}, {1}", pair.Key, pair.Value); }
FOREACH KEYVALUEPAIR: cat, 2 FOREACH KEYVALUEPAIR: dog, 1 FOREACH KEYVALUEPAIR: llama, 0 FOREACH KEYVALUEPAIR: iguana, -1 FOREACH VAR: cat, 2 FOREACH VAR: dog, 1 FOREACH VAR: llama, 0 FOREACH VAR: iguana, -1
Keys. The Keys property returns a collection of type KeyCollection, not an actual List. We can convert it into a List. This property is helpful in many programs.Shows a dictionary
using System; using System.Collections.Generic; var data = new Dictionary<string, int>() { {"cat", 2}, {"dog", 1}, {"llama", 0}, {"iguana", -1} }; // Store keys in a List. var list = new List<string>(data.Keys); // Loop through the List. foreach (string key in list) { Console.WriteLine("KEY FROM LIST: " + key); }
KEY FROM LIST: cat KEY FROM LIST: dog KEY FROM LIST: llama KEY FROM LIST: iguana
Count and Remove. Count returns the number of keys in a dictionary. And Remove eliminates a key (and its value) from the dictionary—if the key is found.
Info Count returns the total number of keys—this is the simplest way to count all pairs in a Dictionary.
Dictionary Count
Warning Remove will not cause an error if the key is not found, but if the key is null, it will cause an exception.
Shows a dictionary
using System; using System.Collections.Generic; var lunch = new Dictionary<string, int>() { {"carrot", 1}, {"pear", 4}, {"apple", 6}, {"kiwi", 3} }; Console.WriteLine("COUNT: " + lunch.Count); // Remove pear. lunch.Remove("pear"); Console.WriteLine("COUNT: " + lunch.Count);
COUNT: 4 COUNT: 3
GetValueOrDefault. This method is available on Dictionary in .NET 5. It safely (with no possible exceptions) gets a value from the Dictionary, or the default value for the value's type.
Dictionary GetValueOrDefault
Info Value types have a default of 0 (or the equivalent to 0) or null. The default can be determined with a default() call.
Here The dictionary is created with a key of "mittens," and we get its value with GetValueOrDefault.
And When we try to get a key that does not exist, the value 0 is returned—0 is the default value for an int.
using System; using System.Collections.Generic; var cats = new Dictionary<string, int>() { { "mittens", 5 } }; // Has value 5. Console.WriteLine(cats.GetValueOrDefault("mittens")); // Not found. Console.WriteLine(cats.GetValueOrDefault("?"));
5 0
TryAdd. With this method (part of .NET 5) we add an entry only if the key is not found. It returns a bool that tells us whether the key was added.
Dictionary TryAdd
Part 1 We call TryAdd, and the key is not found in the dictionary, so it is added with the value we specify (1).
Part 2 We call TryAdd again. But "test" already is present, so TryAdd returns false and the dictionary is not modified.
Part 3 We use GetValueOrDefault and the initial value of "test" is still in the dictionary.
using System; using System.Collections.Generic; var items = new Dictionary<string, int>(); // Part 1: add the string with value 1. bool result = items.TryAdd("test", 1); Console.WriteLine("Added: " + result); // Part 2: the value already exists, so we cannot add it again. bool result2 = items.TryAdd("test", 2); Console.WriteLine("Added: " + result2); // Part 3: the value is still 1. Console.WriteLine(items.GetValueOrDefault("test"));
Added: True Added: False 1
ContainsKey. This commonly-called method sees if a given string is present in a Dictionary. We use string keys here—we look at more types of Dictionaries further on.
Dictionary ContainsKey
Return ContainsKey returns true if the key is found. Otherwise, it returns false. No exception is thrown if the key is missing.
using System; using System.Collections.Generic; var dictionary = new Dictionary<string, int>(); dictionary.Add("apple", 1); dictionary.Add("windows", 5); // See whether Dictionary contains this string. if (dictionary.ContainsKey("apple")) { int value = dictionary["apple"]; Console.WriteLine(value); } // See whether it contains this string. if (!dictionary.ContainsKey("acorn")) { Console.WriteLine(false); }
1 False
Int keys. Dictionary is a generic class. To use it, we must specify a type. This is a good feature—it means we can use an int key just as easily as a string key.
Here In this program, we see an example of a Dictionary with int keys. The values can also be any type.
using System; using System.Collections.Generic; // Use int key type. var data = new Dictionary<int, string>(); data.Add(100, "color"); data.Add(200, "fabric"); // Look up the int. if (data.ContainsKey(200)) { Console.WriteLine("CONTAINS KEY 200"); }
CONTAINS KEY 200
LINQ. Extension methods can be used with Dictionary. We use the ToDictionary method—this is an extension method on IEnumerable. It places keys and values into a new Dictionary.
Detail The program uses lambda expressions. With these small functions, we specify a method directly as an argument.
Lambda
Here The example uses ToDictionary, from System.Linq, on a string array. It creates a lookup table for the strings.
using System; using System.Linq; string[] values = new string[] { "One", "Two" }; // Create Dictionary with ToDictionary. // ... Specify a key creation method, and a value creation method. var result = values.ToDictionary(item => item, item => true); foreach (var pair in result) { Console.WriteLine("RESULT PAIR: {0}, {1}", pair.Key, pair.Value); }
RESULT PAIR: One, True RESULT PAIR: Two, True
ContainsValue. This method tries to find a value in the Dictionary (not a key). It searches the entire collection, as no hashing is available on values.
Dictionary ContainsValue
Note This example will loop through all elements in the Dictionary until it finds a match, or there are no more elements to check.
Note 2 ContainsValue is not as fast as ContainsKey. Using another Dictionary with keys of the values could help speed things up.
using System; using System.Collections.Generic; var data = new Dictionary<string, int>(); data.Add("cat", 1); data.Add("dog", 2); // Use ContainsValue to see if the value is present with any key. if (data.ContainsValue(1)) { Console.WriteLine("VALUE 1 IS PRESENT"); }
VALUE 1 IS PRESENT
Indexer. We do not need to use Add to insert into a Dictionary. We can instead use the indexer with square brackets. This syntax also gets the value at the key.
Warning If we try to get a value at a key that does not exist, an exception is thrown.
Note With the indexer, an exception is not thrown when we assign to a key that already has a value. But with Add, an exception is thrown.
using System; using System.Collections.Generic; var dictionary = new Dictionary<int, int>(); // We can assign with the indexer. dictionary[1] = 2; dictionary[2] = 1; dictionary[1] = 3; // Reassign. // Read with the indexer. // ... An exception occurs if no element exists. Console.WriteLine(dictionary[1]); Console.WriteLine(dictionary[2]);
3 1
Copy. Dictionary provides a constructor that copies all values and keys into a new Dictionary instance. This constructor improves code reuse. It makes copying simpler.
Dictionary Copy
Start The "test" Dictionary in this program is created, and has just 1 key and value pair in it.
Then We create a copy by passing the "test" Dictionary to its constructor. We add a key. The copy has 2 keys—but "test" still has 1.
using System; using System.Collections.Generic; var test = new Dictionary<int, int>(); test[20] = 30; // Copy the dictionary, and add another key, so we now have 2 keys. var copy = new Dictionary<int, int>(test); copy[30] = 40; Console.WriteLine("TEST COUNT: {0}", test.Count); Console.WriteLine("COPY COUNT: {0}", copy.Count);
TEST COUNT: 1 COPY COUNT: 2
Clear. We can erase all pairs with the Clear method. Or we can assign the Dictionary variable to null. This causes little difference in memory usage—the entries are garbage-collected.
Dictionary Clear
using System; using System.Collections.Generic; // Create a 1-key dictionary. var d = new Dictionary<string, bool>(); d.Add("dog", true); Console.WriteLine(d.Count); // Clear the dictionary. d.Clear(); Console.WriteLine(d.Count);
1 0
Dictionary field. Sometimes it is useful to have a Dictionary at the class level, as a field. And if we have a static class, we can initialize the Dictionary at the class level.
using System; using System.Collections.Generic; class Example { Dictionary<int, int> _lookup = new Dictionary<int, int>() { {1, 1}, {2, 3}, {3, 5}, {6, 10} }; public int GetValue() { return _lookup[2]; // Example only. } } class Program { static void Main() { // Create Example object instance. var example = new Example(); // Look up a value from the Dictionary field. Console.WriteLine("RESULT: " + example.GetValue()); } }
RESULT: 3
KeyNotFoundException. This error happens when we access a nonexistent key. With Dictionary we should test keys for existence first, with ContainsKey or TryGetValue.
KeyNotFoundException
using System.Collections.Generic; class Program { static void Main() { var colors = new Dictionary<string, int>() { { "blue", 10 } }; // Use ContainsKey or TryGetValue instead. int result = colors["fuchsia"]; } }
Unhandled Exception: System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary. at System.Collections.Generic.Dictionary`2.get_Item(TKey key) at Program.Main() in ...
Benchmark, StringComparer. When you do a lookup on a Dictionary of string keys, the string must be hashed. If we pass StringComparer.Ordinal to our Dictionary, we have a faster algorithm.
Version 1 We look up the key "Las Vegas" in a Dictionary with no comparer specified in its constructor.
Version 2 In this version we look up the string "Las Vegas" in a Dictionary with StringComparer.Ordinal.
Result When we consider a string as "ordinal," we but gain performance on comparison and hashing (tested in 2021 on .NET 5).
using System; using System.Collections.Generic; using System.Diagnostics; const int _max = 10000000; var data1 = new Dictionary<string, bool>(); data1["Las Vegas"] = true; var data2 = new Dictionary<string, bool>(StringComparer.Ordinal); data2["Las Vegas"] = true; // Version 1: do lookups on Dictionary with default string comparisons. Stopwatch s1 = Stopwatch.StartNew(); for (int i = 0; i < _max; i++) { if (!data1.ContainsKey("Las Vegas")) { return; } } s1.Stop(); // Version 2: do lookups in Dictionary that has StringComparer.Ordinal. Stopwatch s2 = Stopwatch.StartNew(); for (int i = 0; i < _max; i++) { if (!data2.ContainsKey("Las Vegas")) { return; } } s2.Stop(); Console.WriteLine(((double)(s1.Elapsed.TotalMilliseconds * 1000000) / _max).ToString("0.00 ns")); Console.WriteLine(((double)(s2.Elapsed.TotalMilliseconds * 1000000) / _max).ToString("0.00 ns"));
16.40 ns ContainsKey, default comparer 15.17 ns ContainsKey, StringComparer.Ordinal
Benchmark, Keys. Here we compare loops. A foreach-loop on KeyValuePairs is faster than the looping over Keys and accessing values in the loop body.
Version 1 This code loops over the dictionary in a foreach-loop directly, without accessing the Keys property.
Version 2 This version of the code accesses the Keys property, and then looks up each value in a foreach-loop.
Result In 2021 with .NET 5 (for Linux) it is faster to loop over the pairs in a Dictionary and avoid lookups.
using System; using System.Collections.Generic; using System.Diagnostics; const int _max = 1000000; var test = new Dictionary<string, int>(); test["bird"] = 10; test["frog"] = 20; test["cat"] = 60; int sum = 0; // Version 1: use foreach loop directly on Dictionary. var s1 = Stopwatch.StartNew(); for (int i = 0; i < _max; i++) { foreach (var pair in test) { sum += pair.Value; } } s1.Stop(); // Version 2: use foreach loop on Keys, then access values. var s2 = Stopwatch.StartNew(); for (int i = 0; i < _max; i++) { foreach (var key in test.Keys) { sum += test[key]; } } s2.Stop(); Console.WriteLine(s1.Elapsed.TotalMilliseconds); Console.WriteLine(s2.Elapsed.TotalMilliseconds);
22.5618 ms Dictionary foreach 72.231 ms Keys foreach
Summary. The C# Dictionary, like all hash tables, is fascinating. It is fast—and useful in many places. Once we get a handle on its syntax, it is easy to use.
Dot Net Perls is a collection of tested code examples. Pages are continually updated to stay current, with code correctness a top priority.
Sam Allen is passionate about computer languages. In the past, his work has been recommended by Apple and Microsoft and he has studied computers at a selective university in the United States.
This page was last updated on Nov 10, 2023 (simplify).
Home
Changes
© 2007-2024 Sam Allen.