C# Dictionary: Complete Guide [2023]
This article is a complete guide to the Dictionary data structure in C#.
C# Dictionary is a data structure that holds key-value pairs. It's called a Dictionary because the key is used to look up the corresponding value, just like in a real dictionary. The good thing is that the dictionary is a generic, so we can use it to store values of any type.
C# Dictionary Example
Initialization
To initialize a dictionary in C#, we first need to provide the type for the key and the type for the value.
For example, for a dictionary that stores the name and age of a person, the initialization would be:
Dictionary<string, int> nameToAge = new Dictionary<string, int>();
The first type inside the angle brackets is the key type. The second type is the value type.
Initial values
To define initial values at the time of initialization, we use the following syntax:
Dictionary<string, int> nameToAge = new Dictionary<string, int>()
{
{"John", 26},
{"Anna", 34 }
};
The collection-initializer syntax above is like the initialization of an array.
Another way to initialize a dictionary is object initializer introduced in C# 6:
Dictionary<string, int> nameToAge = new Dictionary<string, int>
{
["John"] = 26,
["Anna"] = 34
};
Add item to a dictionary
To add an item to a dictionary, we use the Add method. For example:
nameToAge.Add("Adam", 24);
This would add "Adam" and his age of 24 to the nameToAge dictionary.
Remove the dictionary item
To remove an item from a dictionary, we use the Remove method. For example:
nameToAge.Remove("Adam");
This would remove "Adam" from the nameToAge dictionary.
The remove method uses the key to determine which item to remove.
Update dictionary items
To update an item in a dictionary, we update the value associated with the key. For example:
nameToAge["Adam"] = 24;
This would update Adam's age of 24 to nameToAge dictionary.
Remove all dictionary values
To remove all the values from a dictionary, we use the Clear
method.
For example:
nameToAge.Clear();
This would clear nameToAge dictionary of all items.
Get the number of elements
To get the number of items in the dictionary, we use the Count property.
For example:
int count = nameToAge.Count;
This would get the number of items in nameToAge dictionary.
Duplicate values
In C#, a dictionary can only have one value for a key.
If we add another value with the same key, then we'll get the KeyNotFoundException exception.
For example, if we try to add a value with key "Adam" then we would get:
Dictionary<string, int> nameToAge = new ()
{
{"Adam", 26},
};
nameToAge.Add("Adam", 24);
Here we get the exception because there is already a key "Adam" and the dictionary cannot have two values for the same key.
As developers, we need to handle these exceptions by first checking for the key to exist before adding a value.
To check if a dictionary already has a value, we can use the ContainsKey
method:
nameToAge.ContainsKey("Adam")
It's a good design practice to use values we know are unique.
In the example above, it would be better to use a unique ID instead of a name.
C# Dictionary: Get value by key
To retrieve a value from a dictionary in C#, you can use the TryGetValue method or the indexer.
TryGetValue
The TryGetValue method is a safe way to get a value from a dictionary without having to handle exceptions.
It returns a bool value to let us know if the key was found.
For example, we can use TryGetValue this way:
int age = nameToAge.TryGetValue("Adam", out int a) ? a : default;
The code above will first check if the dictionary has a key "Adam" and if it does, returns its value. If it does not, then age will be set to the default value for int, which is 0.
The "Try" pattern is very common in C# and .NET, I explained it in detail in my article on TryParse.
Indexer
Here's an example of how to get a dictionary value by key:
Dictionary<string, int> dictionary = new Dictionary<string, int>();
dictionary.Add("apple", 1);
dictionary.Add("banana", 2);
int value = dictionary["apple"];
Console.WriteLine(value); // Output: 1
Note that if you try to use the indexer to retrieve a value for a key that does not exist in the dictionary, it will throw a KeyNotFoundException
. To avoid this, you can use the ContainsKey
method to check if the key is present in the dictionary before trying to retrieve the value.
Iterate over a Dictionary
To iterate over keys and values of a dictionary, we can use the foreach loop:
foreach (KeyValuePair<int, string> item in nameToAge)
{
item.Key;
item.Value;
}
The item variable is an object of type KeyValuePair<Tkey, TValue>
which has the properties to provide the key and value.
KeyValuePair is a very simple struct. It only holds two properties - Key and Value:
Get keys and values
Dictionary exposes two read-only properties to get all keys or values:
These properties are useful if we want to iterate over all keys or values of a dictionary.
Internals
C# dictionary uses a hash table as its internal data structure.
Hash tables rely on hash codes to locate an item.
For example, adding an item to a dictionary performs these 3 steps in the background:
- Compute a hash code for the key.
- Verify the key's hash code is not equal to the key already in the dictionary.
- Place the entry in the hash table bucket.
Read my article on Hashset to find out more about hash codes.
Use immutable objects for keys
A dictionary can break if we use a reference type as a key.
That's because Dictionary stores a reference to that object and not the object itself.
So if we change the object after adding it to the dictionary, then we would break the whole dictionary.
Because of that, it's a best practice to use immutable objects, like strings, when using the dictionary.
C# 9.0 in a Nutshell explains why:
If an object’s hashcode changes after it’s been added as a key to a dictionary, the object will no longer be accessible in the dictionary.
TryGetValue vs ContainsKey+Item
TryGetValue and ContainsKey are the two most popular ways of getting a value from a dictionary.
For ContainsKey, it's a two-step process:
- Do the lookup to verify the key exists in the dictionary.
- Do the lookup to get the value from the dictionary based on the key.
On the other hand, TryGetValue does the lookup and gets the value in one step.
Because of the performance, we should always use TryGetValue to get a value from a dictionary.
Dictionary exceptions
These are the most common exceptions we can get from a dictionary:
Exception type | Exception occurs |
---|---|
KeyNotFoundException | If there is no key with the value we are looking up. |
ArgumentOutOfRangeException | If the index that we are looking up is out of range. |
ArgumentNullException | If the key is null. |
ArgumentException | If we try to add a key that already exists. |
To prevent these exceptions, use TryGetValue and TryAdd.
Dictionary vs OrderedDictionary
The main difference between Dictionary and OrderedDictionary is that Dictionary does not guarantee the order in which it will return values, but OrderedDictionary does.
OrderedDictionary is less efficient than Dictionary because insert/delete operations have to be done on an array, with the complexity of O(n) at worst.
Dictionary vs SortedDictionary
SortedDictionary is another class that implements IDictionary.
The main difference between a Dictionary and SortedDictionary is that SortedDictionary uses a binary search tree with O(log n) retrieval, while Dictionary is a hash table of O(1) complexity for access.
Use SortedDictionary if you have an extensive list of items and need them sorted.
ReadOnlyDictionary
ReadOnlyDictionary is an implementation of IDictionary that does not allow adding or deleting items.
It only provides read access through its properties
ReadOnlyDictionary is a decorator wrapper around the regular Dictionary class.
C# Dictionary Performance
The following table shows the complexity of each IDictionary implementation:
Implementation | Complexity |
---|---|
Dictionary, OrderedDictionary | O(1) |
SortedDictionary | O(log n) |
List | O(n) |
Historically, computer scientists have been exploring the most efficient way of searching through a dictionary. Richard Bornat from Middlesex University explained the problem here:
Concurrency
The Dictionary implementation is not thread-safe.
For example, one thread can change the data structure while another thread tries to iterate, causing an exception.
To make a thread-safe dictionary in C#, use the ConcurrentDictionary implementation.
All public and protected members of ConcurrentDictionary are thread-safe and we can use them concurrently from multiple threads.
The ConcurrentDictionary implementation uses tables to keep track of dictionary's state:
Summary
The Dictionary data structure in C# is a collection of key-value pairs.
It's called a Dictionary because the key is used to look up the corresponding value, just like in a real dictionary.
We can initialize the Dictionary using either a collection-initializer or an object initializer.
To manage a dictionary, we use:
- Add method
- Remove method
- Clear method
- Update the value associated with the key
Be careful and catch exceptions when using any of the methods that change the structure, such as Add, Remove, Clear, or Update.
The most common way to retrieve a value from a dictionary is using TryGetValue, which gets a value without throwing exceptions.
Besides the standard Dictionary, there are other implementations of IDictionary interface:
- The Dictionary class does not guarantee the order in which it will return values, but OrderedDictionary does.
- ReadOnlyDictionary does not allow adding or deleting items.
- ConcurrentDictionary uses tables to keep track of the dictionary's state from multiple threads, making it thread-safe.
FAQ
How do I create a dictionary from a list or array in C#?
To create a dictionary from a list or array in C#, you can use the ToDictionary
method from the System.Linq
namespace. This method takes a sequence of elements and a function that specifies how to create the key and value for each element.
Here's an example of creating a dictionary from a list of strings:
List<string> list = new List<string> { "apple", "banana", "cherry" };
Dictionary<int, string> dictionary = list.ToDictionary(i => list.IndexOf(i), i => i);
foreach (KeyValuePair<int, string> kvp in dictionary)
{
Console.WriteLine($"Key: {kvp.Key}, Value: {kvp.Value}");
}
Output:
Key: 0, Value: apple
Key: 1, Value: banana
Key: 2, Value: cherry
You can also use the ToDictionary
method to create a dictionary from an array of elements.
string[] array = new string[] { "apple", "banana", "cherry" };
Dictionary<int, string> dictionary = array.ToDictionary(i => Array.IndexOf(array, i), i => i);
foreach (KeyValuePair<int, string> kvp in dictionary)
{
Console.WriteLine($"Key: {kvp.Key}, Value: {kvp.Value}");
}
Output:
Key: 0, Value: apple
Key: 1, Value: banana
Key: 2, Value: cherry
Note that if the key function returns duplicate keys for two or more elements, the ToDictionary
method will throw an exception.
What are valid C# dictionary keys?
In C#, all keys that match the type of the dictionary are valid.
The only catch to be aware of is that the key cannot be null.
If we try to use null as a key, then we'll get an ArgumentNullException exception:
System.ArgumentNullException: Value cannot be null. (Parameter 'key')
Can we have a dictionary inside a dictionary?
Dictionary can have a dictionary as its value.
For example:
Dictionary<string, Dictionary<int, string>> nameToAgeByBirthDate = new Dictionary<string, Dictionary<int, string>>();
Here nameToAgeByBirthDate has 2 key-value pairs.
Even though C# supports nested dictionaries, I prefer to avoid them.
It makes the code more complex with no benefit. A list or array is always a better choice.
Can key and value be of the same type?
In C#, the key and value of a dictionary can have the same type. For example, to create a string-to-string mapping, we can use a Dictionary<string, string>
.
Josip Miskovic is a software developer at Americaneagle.com. Josip has 10+ years in experience in developing web applications, mobile apps, and games.
Read more posts →Last modified on:
- C# Dictionary Example
- Initialization
- Initial values
- Add item to a dictionary
- Remove the dictionary item
- Update dictionary items
- Remove all dictionary values
- Get the number of elements
- Duplicate values
- C# Dictionary: Get value by key
- TryGetValue
- Indexer
- Iterate over a Dictionary
- Get keys and values
- Internals
- Use immutable objects for keys
- TryGetValue vs ContainsKey+Item
- Dictionary exceptions
- Dictionary vs OrderedDictionary
- Dictionary vs SortedDictionary
- ReadOnlyDictionary
- C# Dictionary Performance
- Concurrency
- Summary
- FAQ
- How do I create a dictionary from a list or array in C#?
- What are valid C# dictionary keys?
- Can we have a dictionary inside a dictionary?
- Can key and value be of the same type?
I've used these principles to increase my earnings by 63% in two years. So can you.
Dive into my 7 actionable steps to elevate your career.