Dictionary in C#

Learn Dictionary in C# with practical examples, explanations, best practices, and real-world coding techniques.

What Is Dictionary<TKey, TValue> in C#?

Dictionary<TKey, TValue> is a generic collection in C# that stores data as key-value pairs. Each key identifies a corresponding value, allowing applications to retrieve information efficiently using the key instead of searching through every element.

A dictionary is commonly used for lookups such as finding a user by ID, retrieving a product by its code, mapping configuration names to values, counting occurrences, and associating one piece of information with another.

Key-Value Pair Structure

Every dictionary entry consists of a key and a value. The key must be unique within the dictionary, while multiple keys can have values that are equal.

Key       Value
-------------------
101       "Asha"
102       "Rahul"
103       "Priya"

In this example, 101, 102, and 103 are keys and the corresponding names are values.

Creating a Dictionary in C#

The generic dictionary is available through the System.Collections.Generic namespace.

using System.Collections.Generic;

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

The first type parameter specifies the key type and the second specifies the value type. Here, the dictionary uses int keys and string values.

Initializing a Dictionary with Values

A dictionary can be initialized with key-value pairs when it is created.

var users = new Dictionary<int, string>
{
    { 101, "Asha" },
    { 102, "Rahul" },
    { 103, "Priya" }
};

Console.WriteLine(users[102]);
// Rahul

Adding Elements with Add()

The Add() method inserts a new key-value pair into the dictionary. The key must not already exist.

var scores = new Dictionary<string, int>();

scores.Add("Asha", 95);
scores.Add("Rahul", 88);
scores.Add("Priya", 91);

Console.WriteLine(scores["Asha"]);
// 95

Attempting to add another entry with an existing key using Add() throws an ArgumentException.

Adding or Updating with the Indexer

The dictionary indexer can both add a new key and update an existing key. This makes it useful when you do not need to distinguish between the two operations.

var scores = new Dictionary<string, int>();

scores["Asha"] = 95;
scores["Rahul"] = 88;

// Update existing value
scores["Asha"] = 98;

Console.WriteLine(scores["Asha"]);
// 98

Retrieving a Value by Key

A value can be retrieved using its key with the dictionary indexer.

var products = new Dictionary<int, string>
{
    { 1001, "Laptop" },
    { 1002, "Keyboard" },
    { 1003, "Mouse" }
};

string product = products[1002];

Console.WriteLine(product);
// Keyboard

If the requested key does not exist, accessing it through the indexer throws a KeyNotFoundException.

Safe Lookup with TryGetValue()

When a key may not exist, TryGetValue() is often the preferred lookup pattern. It returns true when the key exists and places the corresponding value in the output variable.

var users = new Dictionary<int, string>
{
    { 101, "Asha" },
    { 102, "Rahul" }
};

if (users.TryGetValue(102, out string? name))
{
    Console.WriteLine(name);
}
else
{
    Console.WriteLine("User not found");
}

This avoids performing a separate lookup followed by another indexed access and also avoids an exception when the key is missing.

Checking Whether a Key Exists

Use ContainsKey() when you only need to know whether a key is present.

var users = new Dictionary<int, string>
{
    { 101, "Asha" },
    { 102, "Rahul" }
};

Console.WriteLine(users.ContainsKey(101));
// True

Console.WriteLine(users.ContainsKey(999));
// False

Checking for a Value

ContainsValue() checks whether at least one dictionary entry contains a specified value.

var users = new Dictionary<int, string>
{
    { 101, "Asha" },
    { 102, "Rahul" }
};

Console.WriteLine(users.ContainsValue("Rahul"));
// True

Unlike key lookup, checking for a value generally requires examining the entries and therefore has linear complexity.

Removing Entries

The Remove() method removes an entry using its key. It returns true when the entry was removed successfully.

var users = new Dictionary<int, string>
{
    { 101, "Asha" },
    { 102, "Rahul" },
    { 103, "Priya" }
};

bool removed = users.Remove(102);

Console.WriteLine(removed);
// True

Console.WriteLine(users.Count);
// 2

Clearing a Dictionary

The Clear() method removes all key-value pairs from the dictionary.

var scores = new Dictionary<string, int>
{
    { "Asha", 95 },
    { "Rahul", 88 }
};

scores.Clear();

Console.WriteLine(scores.Count);
// 0

Iterating Through a Dictionary

A dictionary can be traversed using foreach. Each iteration provides a KeyValuePair<TKey, TValue>.

var users = new Dictionary<int, string>
{
    { 101, "Asha" },
    { 102, "Rahul" },
    { 103, "Priya" }
};

foreach (var user in users)
{
    Console.WriteLine($"ID: {user.Key}, Name: {user.Value}");
}

Accessing Keys and Values

The Keys and Values properties provide collections that can be used when only one side of the dictionary is required.

var scores = new Dictionary<string, int>
{
    { "Asha", 95 },
    { "Rahul", 88 }
};

foreach (var name in scores.Keys)
{
    Console.WriteLine(name);
}

foreach (var score in scores.Values)
{
    Console.WriteLine(score);
}

Dictionary Count

The Count property returns the number of key-value pairs currently stored.

var users = new Dictionary<int, string>
{
    { 1, "Asha" },
    { 2, "Rahul" },
    { 3, "Priya" }
};

Console.WriteLine(users.Count);
// 3

Dictionary with Custom Objects

Dictionaries become particularly useful when an application needs to retrieve objects using an identifier.

class Product
{
    public int Id { get; set; }
    public string Name { get; set; } = "";
    public decimal Price { get; set; }
}

var products = new Dictionary<int, Product>
{
    {
        101,
        new Product
        {
            Id = 101,
            Name = "Laptop",
            Price = 75000
        }
    },
    {
        102,
        new Product
        {
            Id = 102,
            Name = "Keyboard",
            Price = 2500
        }
    }
};

if (products.TryGetValue(101, out Product? product))
{
    Console.WriteLine(product.Name);
    Console.WriteLine(product.Price);
}

Dictionary with String Keys

String keys are commonly used for configuration values, labels, user preferences, and other named data.

var configuration = new Dictionary<string, string>
{
    { "Environment", "Production" },
    { "Region", "Asia" },
    { "Version", "2.0" }
};

Console.WriteLine(configuration["Environment"]);
// Production

Counting Frequencies with a Dictionary

A dictionary is commonly used to count how frequently values occur. The key represents the value being counted and the dictionary value stores its current frequency.

var numbers = new[] { 1, 2, 1, 3, 2, 1 };

var frequency = new Dictionary<int, int>();

foreach (var number in numbers)
{
    if (frequency.ContainsKey(number))
    {
        frequency[number]++;
    }
    else
    {
        frequency[number] = 1;
    }
}

foreach (var item in frequency)
{
    Console.WriteLine($"{item.Key}: {item.Value}");
}

Using TryGetValue for Frequency Counting

TryGetValue() can make frequency-counting code concise while avoiding an exception for a missing key.

var words = new[] { "C#", "Java", "C#", "Python", "Java", "C#" };

var frequency = new Dictionary<string, int>();

foreach (var word in words)
{
    if (frequency.TryGetValue(word, out int count))
    {
        frequency[word] = count + 1;
    }
    else
    {
        frequency[word] = 1;
    }
}

foreach (var item in frequency)
{
    Console.WriteLine($"{item.Key}: {item.Value}");
}

Using Collections as Dictionary Values

The value type of a dictionary can itself be a collection. This is useful for representing one-to-many relationships.

var skillsByDeveloper = new Dictionary<string, List<string>>
{
    {
        "Asha",
        new List<string> { "C#", "SQL", "Azure" }
    },
    {
        "Rahul",
        new List<string> { "Java", "Spring", "Docker" }
    }
};

foreach (var skill in skillsByDeveloper["Asha"])
{
    Console.WriteLine(skill);
}

Dictionary and LINQ

LINQ can be used to filter and transform dictionary entries. The dictionary can be treated as a sequence of key-value pairs.

using System.Linq;

var scores = new Dictionary<string, int>
{
    { "Asha", 95 },
    { "Rahul", 72 },
    { "Priya", 88 },
    { "Arun", 64 }
};

var highScores = scores
    .Where(item => item.Value >= 80)
    .ToDictionary(item => item.Key, item => item.Value);

foreach (var item in highScores)
{
    Console.WriteLine($"{item.Key}: {item.Value}");
}

Dictionary Time Complexity

A dictionary is implemented using hashing. Under normal conditions, key insertion, lookup, and removal are expected to be efficient.

Operation Typical Complexity Notes
Lookup by key O(1) average Hash-based lookup
Add O(1) average May occasionally require resizing
Update by key O(1) average Requires locating the key
Remove by key O(1) average Hash-based lookup
ContainsKey O(1) average Checks the key
ContainsValue O(n) May inspect every entry
Iteration O(n) Visits every entry

Dictionary Keys Must Be Unique

A dictionary cannot contain two entries with the same key. If the application needs multiple values associated with one key, the value can instead be a collection such as List<T>.

var coursesByStudent = new Dictionary<int, List<string>>
{
    {
        101,
        new List<string> { "C#", "SQL" }
    },
    {
        102,
        new List<string> { "Java", "Spring" }
    }
};

coursesByStudent[101].Add("Azure");

Console.WriteLine(
    string.Join(", ", coursesByStudent[101])
);
// C#, SQL, Azure

Choosing a Dictionary Key

A dictionary key should represent a stable identifier that can reliably distinguish one entry from another. Common keys include numeric IDs, strings, enums, and other types with suitable equality and hashing behavior.

For custom key types, correct equality and hash-code behavior is especially important because the dictionary relies on those operations to locate entries.

Dictionary vs List<T>

A List<T> and a dictionary solve different access problems. A list is organized around position, while a dictionary is organized around keys.

Feature List<T> Dictionary<TKey, TValue>
Primary access Index Key
Lookup O(n) generally O(1) average by key
Duplicate values Allowed Allowed
Duplicate keys Not applicable Not allowed
Best suited for Ordered sequential data Key-based lookup

Common Dictionary Mistakes

  • Trying to add the same key more than once with Add().
  • Accessing a key with the indexer without checking whether it exists.
  • Using ContainsValue() when the application actually needs key-based lookup.
  • Assuming dictionary entries are accessed by numeric index like a list.
  • Using mutable objects as keys without understanding equality and hashing behavior.
  • Choosing a dictionary when the application primarily requires sequential ordering and index access.

Practical Example: Product Lookup

A product catalog can use a dictionary to associate product IDs with product objects. This avoids scanning a complete list whenever a product needs to be retrieved by ID.

record Product(int Id, string Name, decimal Price);

var products = new Dictionary<int, Product>
{
    { 1001, new Product(1001, "Laptop", 75000) },
    { 1002, new Product(1002, "Keyboard", 2500) },
    { 1003, new Product(1003, "Mouse", 1200) }
};

if (products.TryGetValue(1002, out Product? product))
{
    Console.WriteLine(product.Name);
    Console.WriteLine($"Price: {product.Price}");
}

Key Takeaways

  • Dictionary<TKey, TValue> stores data as key-value pairs.
  • Every key must be unique within the dictionary.
  • Add() inserts a new key-value pair and rejects duplicate keys.
  • The indexer can add a new key or update an existing value.
  • TryGetValue() provides a safe way to retrieve values when a key may not exist.
  • ContainsKey() checks whether a key is present.
  • Lookup, insertion, and removal are typically O(1) on average.
  • ContainsValue() generally requires O(n) time.
  • Dictionaries are useful for fast key-based lookups, mappings, and frequency counting.

Code Examples

using System;
using System.Collections.Generic;

var scores = new Dictionary<string, int>
{
    { "Asha", 95 },
    { "Rahul", 88 }
};

scores["Asha"] = 98;
scores["Priya"] = 91;

Console.WriteLine(scores["Asha"]);
Console.WriteLine(scores["Priya"]);
    
using System;
using System.Collections.Generic;

var users = new Dictionary<int, string>
{
    { 101, "Asha" },
    { 102, "Rahul" }
};

if (users.TryGetValue(102, out string? name))
{
    Console.WriteLine($"User: {name}");
}
else
{
    Console.WriteLine("User not found");
}

Console.WriteLine(users.ContainsKey(999));
// False
    
using System;
using System.Collections.Generic;

var numbers = new[] { 1, 2, 1, 3, 2, 1 };

var frequency = new Dictionary<int, int>();

foreach (var number in numbers)
{
    if (frequency.TryGetValue(number, out int count))
    {
        frequency[number] = count + 1;
    }
    else
    {
        frequency[number] = 1;
    }
}

foreach (var item in frequency)
{
    Console.WriteLine($"{item.Key}: {item.Value}");
}
    

Pro Tip

Use Dictionary<TKey, TValue> when your application naturally identifies data with a key. Prefer TryGetValue() when a key may be missing, and use List<T> instead when the main requirement is ordered data with indexed access.

🎨 IgKnight Docs

Master HTML, CSS, JS, Python, .NET and more with easy-to-follow lessons and practical code examples.

© 2025 IgKnight Learning Platform. All rights reserved.