How to Use Dictionary in C# with Example?

In C#, a dictionary is a collection that stores key-value pairs in a way that enables quick retrieval of values based on their associated keys. It is one of the most versatile and commonly used data structures, offering significant performance benefits for certain types of applications. The Dictionary class is a part of the System.Collections.Generic namespace, which provides a generic collection that ensures type safety by allowing users to define both the key and value types.

In C#, a Dictionary is a collection of key-value pairs that provides fast lookup and retrieval of data. Each key in a Dictionary must be unique and cannot be null, while the values can be duplicates and null. The Dictionary is a part of the System.Collections.Generic namespace and is a generic type, allowing for type-safe data storage.

Utilizing a dictionary in C# involves understanding its operations such as adding items, accessing values, and handling duplicates. This tutorial will provide practical examples to help developers effectively use the Dictionary class. Through these examples, one can learn how to perform essential dictionary operations and discover best practices for their application in real-world coding scenarios.

What are Dictionaries in C#?

In C#, a Dictionary is a collection of keys and values, known as key/value pairs. Each unique key maps to a value, enabling quick data retrieval. It is part of the System.Collections.Generic namespace.

The basic structure of a Dictionary in C# is provided by the following syntax:

Dictionary<TKey, TValue> name = new Dictionary<TKey, TValue>();

Where TKey represents the type of keys and TValue the type of values.

Consider these key characteristics:

  • Keys must be unique and cannot be null.
  • Values can be duplicated, and null values are permissible.
  • The Dictionary is unordered, meaning the order of items is not guaranteed to be consistent.

Creating a Dictionary: One initializes a Dictionary with the new keyword:

Dictionary<int, string> employees = new Dictionary<int, string>();

Adding Items: To add a key/value pair, one uses the Add method:

employees.Add(1, "John Doe");

Accessing Values: Use the key to access its corresponding value:

string employeeName = employees[1];

Iterating Through a Dictionary: Looping over a Dictionary is straightforward with a foreach loop, iterating through each KeyValuePair:

foreach (KeyValuePair<int, string> employee in employees)
{
    Console.WriteLine($"ID: {employee.Key}, Name: {employee.Value}");
}

Handling Exceptions: Attempting to access a non-existent key throws a KeyNotFoundException. Therefore, always ensure the key exists before accessing it:

if (employees.ContainsKey(key))
{
    Console.WriteLine(employees[key]);
}

Create and Initialize Dictionaries in C#

In C#, dictionaries are powerful data structures used for storing key-value pairs with fast lookup. They are created and used with the Dictionary<TKey, TValue> class.

Using the Dictionary Class

To create a dictionary in C#, one must define the type of keys and values it will hold. This is done by specifying the types within angle brackets. Here’s how to instantiate a dictionary with string keys and int values:

Dictionary<string, int> ages = new Dictionary<string, int>();

To add elements to the dictionary, the Add() method is utilised:

ages.Add("Alice", 30);
ages.Add("Bob", 25);

One can also check for the existence of a key using ContainsKey:

bool hasAlice = ages.ContainsKey("Alice");

Initialization with Collection Initializer

Dictionaries can be initialized concisely using a collection initializer. This allows for adding multiple key-value pairs at the time of creation:

Dictionary<string, int> ages = new Dictionary<string, int>
{
    {"Alice", 30},
    {"Bob", 25}
};

The initialization block shouldn’t contain duplicate keys to ensure that the keys are unique and the dictionary remains consistent.

Manipulate C# Dictionary Elements

In C#, dictionaries allow for efficient data storage and retrieval using key-value pairs. Proper manipulation of these elements is fundamental to leveraging the full potential of dictionaries.

Adding Elements

To add elements to a Dictionary, one uses the Add method, specifying the key and the value. Keys must be unique within a Dictionary.

var dictionary = new Dictionary<int, string>();
dictionary.Add(1, "apple");

Note: Utilizing the indexer to assign a value to a new key also adds an element.

dictionary[2] = "banana";

Accessing Elements

Elements are accessed using their keys. If a key is not found, accessing it will throw a KeyNotFoundException.

string value = dictionary[1]; // Returns "apple"

To safely access elements, TryGetValue can be used, which doesn’t throw an exception for missing keys.

if (dictionary.TryGetValue(1, out string result))
{
    // Use result
}

Updating Elements

To update an element, assign a new value to an existing key using the indexer.

dictionary[1] = "avocado"; // Updates the value for key 1

It’s important to ensure the key exists before updating to prevent adding a new element unintentionally.

Removing Elements

To remove an element, Remove is used with the key.

bool success = dictionary.Remove(1); // Returns true if the removal was successful

If the operation needs to be verified, one should check the boolean result of Remove.

Working with C# Dictionary Keys and Values

Interacting with keys and values is fundamental when managing a Dictionary in C#. This section covers the methods to retrieve all keys, all values, and both as key-value pairs from a Dictionary.

Retrieving All Keys

To retrieve all the keys from a Dictionary, one can use the Keys property. This property returns a collection of all keys contained within the Dictionary. Here is an example of how to get all the keys:

Dictionary<int, string> dictionary = new Dictionary<int, string>();
dictionary.Add(1, "value1");
dictionary.Add(2, "value2");
dictionary.Add(3, "value3");

ICollection<int> keys = dictionary.Keys;

foreach (int key in keys)
{
    Console.WriteLine(key); // Outputs: 1 2 3
}

Retrieving All Values

Similarly, to access all the values stored in a Dictionary, use the Values property. This provides a collection of all values in the order corresponding to their keys. Below is an example:

ICollection<string> values = dictionary.Values;

foreach (string value in values)
{
    Console.WriteLine(value); // Outputs: value1 value2 value3
}

Key and Value Pairs

The KeyValuePair<TKey, TValue> structure is utilized to work with each distinct key and value as a pair. To enumerate over each pair in a Dictionary, the foreach loop is commonly used with the dictionary itself, as it implements IEnumerable<KeyValuePair<TKey, TValue>>. The following example demonstrates this usage:

foreach (KeyValuePair<int, string> kvp in dictionary)
{
    Console.WriteLine($"Key: {kvp.Key}, Value: {kvp.Value}");
    // Outputs:
    // Key: 1, Value: value1
    // Key: 2, Value: value2
    // Key: 3, Value: value3
}

Iterating Through a Dictionary in C#

When one needs to access each key-value pair within a C# dictionary, they can use several methods. The foreach loop offers a straightforward way to iterate, while LINQ queries can provide more complex filtering and selection mechanisms.

Using foreach Loop

Dictionary<string, int> ageDictionary = new Dictionary<string, int>() {
    {"Alice", 30},
    {"Bob", 25},
    {"Catherine", 27}
};

foreach (KeyValuePair<string, int> kvp in ageDictionary)
{
    Console.WriteLine("Key = {0}, Value = {1}", kvp.Key, kvp.Value);
}
  • Key and Value represent the pair components within the dictionary.
  • The foreach loop simplifies iteration by automatically enumerating through all entries.

Using LINQ Queries

using System.Linq;

Dictionary<string, int> ageDictionary = new Dictionary<string, int>() {
    {"Alice", 30},
    {"Bob", 25},
    {"Catherine", 27}
};

var filteredAges = from age in ageDictionary
                   where age.Value > 26
                   select age;

foreach (var age in filteredAges)
{
    Console.WriteLine("Key = {0}, Value = {1}", age.Key, age.Value);
}
  • LINQ queries are useful for filtering dictionaries based on a condition.
  • This example selects entries where the age is greater than 26 before iterating through them.

Dictionary Performance Considerations

When utilizing a Dictionary<TKey,TValue> in C#, it’s crucial to consider its performance implications. A dictionary’s performance can largely be gauged by two factors: time complexity and memory overhead.

Time Complexity:

  • Search operations in a dictionary, such as finding a value or checking for the existence of a key, typically operate in O(1) time, or constant time. This efficiency holds as long as the hash function used to index the keys is good and provides a uniform distribution.
  • Insert and remove operations are also expected to run in O(1) when the hash function is ideal. However, poor hash functions may result in hash collisions, leading to longer search times.

Memory Overhead:

  • Each entry in a Dictionary<TKey,TValue> includes not only the key and value but also overhead for the data structure. As a result, dictionaries may consume more memory than a list of tuples or other simple data structures.
  • The dictionary is initialized with a default capacity, which increases as more elements are added. The resizing operation can be expensive; initializing the dictionary with a size estimate can mitigate this issue.

Collisions:

  • Collisions can degrade the dictionary’s performance. Developers should avoid them by ensuring the GetHashCode method for the key type is properly implemented to reduce the likelihood of two different keys generating the same hash code.

Best Practices:

  • Use keys with a powerful hash function to maintain dictionary efficiency.
  • Pre-size the dictionary if the number of elements is known in advance.
  • Understand the equality comparer, as it affects both performance and correctness of the dictionary operations.

C# Dictionary Examples

Dictionaries in C# provide a robust structure for associating keys with values in a type-safe way. Examples include tracking word occurrences, organizing data, and caching expensive computations.

Storing a Word Count

A common use of a dictionary is to store the frequency of words in a block of text. Given a string array of words, one can count the occurrences of each word as follows:

Dictionary<string, int> wordCount = new Dictionary<string, int>();
foreach (string word in words)
{
    if (wordCount.ContainsKey(word))
    {
        wordCount[word]++;
    }
    else
    {
        wordCount[word] = 1;
    }
}

Key-Value Pairs:

  • Key: The word
  • Value: How often the word appears

Grouping Data by Key

Dictionaries are excellent for grouping items by a common key. An example scenario is categorizing products by their type:

Dictionary<string, List<Product>> productsByType = new Dictionary<string, List<Product>>();
foreach (Product product in productList)
{
    if (!productsByType.ContainsKey(product.Type))
    {
        productsByType[product.Type] = new List<Product>();
    }
    productsByType[product.Type].Add(product);
}

Mapping Structure:

KeyValue
Product TypeList of products of this type

Handling Exceptions and Validations

When using dictionaries in C#, managing potential exceptions effectively is crucial to maintain robust and error-free code, particularly when working with keys.

KeyNotFoundException

To avoid unhandled exceptions when accessing dictionary elements, one should always check if a key exists using ContainsKey method before attempting retrieval. A KeyNotFoundException occurs when trying to retrieve an item with a key that is not present in the dictionary. For handling this exception, one could use a try-catch block:

try
{
    var value = myDictionary[key];
}
catch (KeyNotFoundException e)
{
    // Handle the exception, e.g., by logging the error or providing a default value.
}

ArgumentException

When adding entries to a dictionary, an ArgumentException is thrown if a duplicate key is being inserted. It’s important to ensure that keys are unique to avoid this exception. To handle this case, consider verifying key uniqueness or catching the exception as follows:

try
{
    myDictionary.Add(key, value);
}
catch (ArgumentException e)
{
    // Respond to the duplicate key issue, e.g., by updating the existing key's value.
}

Conducting proper validations and exception handling guarantees that the dictionary operates smoothly and without unexpected crashes due to key-related issues.

Read-Only Dictionaries in C#

For scenarios where dictionary data should not be modified after creation, C# provides read-only dictionaries. The ReadOnlyDictionary<TKey,TValue> class wraps an existing IDictionary<TKey,TValue> instance, preventing any modification to its elements.

var originalDictionary = new Dictionary<string, int>
{
    {"apple", 1},
    {"banana", 2}
};

var readOnlyDictionary = new ReadOnlyDictionary<string, int>(originalDictionary);
// Attempting to modify readOnlyDictionary here would result in a compile-time error.

Conclusion

Dictionaries in C# are powerful ways to store and manage key-value pairs. They offer fast retrieval, ease of use, and flexibility that is essential in many programming scenarios. Users should remember the following key points about using dictionaries:

  • Initialization: A dictionary is initialized by defining the key and value types.
  • Adding elements: The Add method or the indexer can be used to insert elements.
  • Retrieval: Use keys to efficiently fetch values with the indexer.
  • Removing elements: The Remove method deletes elements based on the key.
  • Iteration: A dictionary can be traversed using a foreach loop.

In this C# tutorial, I have explained how to use a dictionary in C# with real examples.

You may also like: