C# Dictionary guide — add, lookup, iterate, and common patterns
Dictionary<TKey, TValue> is the go-to collection for fast key-based lookups. It provides O(1) average-case performance for add, remove, and lookup using a hash table internally.
Create and Add Entries
C# Example Code
// Create with initial capacity (avoids resizing when size is known)
var scores = new Dictionary<string, int>();
// Add entries
scores.Add("Alice", 95);
scores.Add("Bob", 87);
scores.Add("Carol", 92);
// Collection initializer syntax
var config = new Dictionary<string, string>
{
["host"] = "localhost",
["port"] = "5432",
["database"] = "mydb"
};Add throws ArgumentException if the key already exists. Use the indexer [key] = value to add or overwrite:
C# Example Code
scores["Alice"] = 98; // update existing
scores["Dave"] = 76; // add newTryGetValue — Safe Lookup Without Exceptions
Avoid double-lookup by combining existence check and retrieval in one call.
C# Example Code
// BAD — checks twice (ContainsKey + indexer)
if (scores.ContainsKey("Alice"))
{
int s = scores["Alice"]; // ❌ second hash lookup
}
// GOOD — single lookup
if (scores.TryGetValue("Alice", out int score))
{
Console.WriteLine($"Alice: {score}"); // Alice: 98
}
else
{
Console.WriteLine("Not found");
}ContainsKey and ContainsValue
C# Example Code
Console.WriteLine(scores.ContainsKey("Bob")); // True
Console.WriteLine(scores.ContainsKey("Eve")); // False
// ContainsValue is O(n) — scans all values
Console.WriteLine(scores.ContainsValue(87)); // TrueRemove Entries
C# Example Code
bool removed = scores.Remove("Dave");
Console.WriteLine(removed); // True
// Remove and retrieve the value in one call (.NET 5+)
if (scores.Remove("Bob", out int bobScore))
Console.WriteLine($"Removed Bob with score {bobScore}"); // 87Iterating a Dictionary
C# Example Code
// Iterate key-value pairs (order is not guaranteed)
foreach (KeyValuePair<string, int> pair in scores)
Console.WriteLine($"{pair.Key}: {pair.Value}");
// Deconstruct the pair (C# 7+)
foreach (var (name, value) in scores)
Console.WriteLine($"{name}: {value}");
// Keys only
foreach (string key in scores.Keys)
Console.WriteLine(key);
// Values only
foreach (int val in scores.Values)
Console.WriteLine(val);GetValueOrDefault — Fallback Without Try/Catch
C# Example Code
int aliceScore = scores.GetValueOrDefault("Alice", 0); // 98
int eveScore = scores.GetValueOrDefault("Eve", 0); // 0 (default)
// Without a default, returns the type default (0 for int, null for reference types)
int missing = scores.GetValueOrDefault("Nobody"); // 0TryAdd — Add Only If Key Is Absent
C# Example Code
bool added = scores.TryAdd("Frank", 81); // True — added
bool dup = scores.TryAdd("Alice", 55); // False — Alice already exists, value unchanged
Console.WriteLine(scores["Alice"]); // 98Common Patterns
Counting Occurrences
C# Example Code
string[] words = { "apple", "banana", "apple", "cherry", "banana", "apple" };
var counts = new Dictionary<string, int>();
foreach (string word in words)
{
counts.TryGetValue(word, out int current);
counts[word] = current + 1;
}
// Shorter with GetValueOrDefault
foreach (string word in words)
counts[word] = counts.GetValueOrDefault(word) + 1;
foreach (var (word, count) in counts)
Console.WriteLine($"{word}: {count}");
// apple: 3, banana: 2, cherry: 1Grouping Items by a Key
C# Example Code
var people = new[]
{
new { Name = "Alice", Dept = "Engineering" },
new { Name = "Bob", Dept = "Marketing" },
new { Name = "Carol", Dept = "Engineering" },
new { Name = "Dave", Dept = "Marketing" },
};
var byDept = new Dictionary<string, List<string>>();
foreach (var person in people)
{
if (!byDept.ContainsKey(person.Dept))
byDept[person.Dept] = new List<string>();
byDept[person.Dept].Add(person.Name);
}
// With LINQ — same result, more concise
var byDeptLinq = people
.GroupBy(p => p.Dept)
.ToDictionary(g => g.Key, g => g.Select(p => p.Name).ToList());Lookup Table / Dispatcher
C# Example Code
var handlers = new Dictionary<string, Action<string>>
{
["greet"] = name => Console.WriteLine($"Hello, {name}!"),
["shout"] = name => Console.WriteLine(name.ToUpper()),
["reverse"] = name => Console.WriteLine(new string(name.Reverse().ToArray())),
};
string command = "greet";
string arg = "World";
if (handlers.TryGetValue(command, out var handler))
handler(arg); // Hello, World!
else
Console.WriteLine($"Unknown command: {command}");Nested Dictionaries
C# Example Code
// Matrix: row key → column key → value
var matrix = new Dictionary<string, Dictionary<string, double>>
{
["Alice"] = new() { ["Math"] = 95.0, ["Science"] = 88.5 },
["Bob"] = new() { ["Math"] = 72.0, ["Science"] = 91.0 },
};
if (matrix.TryGetValue("Alice", out var row) &&
row.TryGetValue("Math", out double mathScore))
{
Console.WriteLine($"Alice Math: {mathScore}"); // 95
}Quick Reference
| Operation | Code |
|---|---|
| Add (throws if duplicate) | dict.Add(key, value) |
| Add or overwrite | dict[key] = value |
| Safe add (no overwrite) | dict.TryAdd(key, value) |
| Safe lookup | dict.TryGetValue(key, out var val) |
| Lookup with fallback | dict.GetValueOrDefault(key, fallback) |
| Key exists? | dict.ContainsKey(key) |
| Remove entry | dict.Remove(key) |
| Remove + retrieve | dict.Remove(key, out var val) |
| Iterate pairs | foreach (var (k, v) in dict) |
| Count entries | dict.Count |
| Empty the dictionary | dict.Clear() |