Dictionary (Key-Value Pairs)

A List answers "what's at position 5?". A Dictionary answers "what's the value for this key?" — a username, a product code, a country. It maps unique keys to values and finds them almost instantly, which makes it the go-to structure for lookups, caches, and counting. It's one of the most useful collections you'll ever learn.

Learn Dictionary (Key-Value Pairs) in our free C# course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick recall.

Part of the free C# course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.

What You'll Learn

💡 Real-World Analogy

A dictionary is exactly like a physical dictionary or phone book . You don't read every page to find "aardvark" — you jump straight to the word (the key ) and read its definition (the value ). Each word appears once, and lookup is instant because the book is organised for it. That's why C# borrowed the name: unique keys, fast lookups, one definition per word.

1. Creating & Using a Dictionary

Declare a dictionary with both types: Dictionary<string, string> maps text keys to text values. Add entries with Add or the indexer, read with dict[key] , and check the size with Count . The indexer overwrites an existing key; Add throws if the key is already present. Iterate the pairs with foreach over KeyValuePair .

2. Reading Safely

The biggest beginner trap: reading a key that isn't there throws KeyNotFoundException . The two safe approaches are ContainsKey (check, then read) and TryGetValue (check and fetch in one lookup). Prefer TryGetValue — it's faster and reads cleanly.

Your turn. Build a small phone book — add a contact and look one up safely.

3. The Counting Pattern

Counting occurrences is the single most common dictionary task — tallying votes, word frequencies, items in a cart. The idea: for each item, if the key exists add one, otherwise start it at one. This pattern shows up constantly, so it's worth committing to memory.

🔎 Deep Dive: GetValueOrDefault

GetValueOrDefault(key) returns the value if the key exists, or a fallback (the type's default, or one you supply) if it doesn't — never throwing. It collapses the whole counting pattern into a single elegant line: tally[c] = tally.GetValueOrDefault(c) + 1; .

A note on ordering: a standard Dictionary makes no promise about iteration order. If you need keys sorted, use a SortedDictionary , or sort the keys yourself when you enumerate.

🧩 Reorder Challenge

These six lines count letters in "moon" and print the count for 'o' . Order them so it prints o appears 2 times .

Why: word must exist before the loop reads it, and the tally dictionary must exist before the loop fills it. The loop must finish counting before the final WriteLine reads tally['o'] , which by then is 2 .

🧠 Quick Recall

5 — assigning with the indexer to an existing key overwrites it, so the second assignment wins.

False 0 — key "y" is absent, so TryGetValue returns false and sets v to its default, 0 .

-1 — key "m" doesn't exist, so GetValueOrDefault returns the supplied fallback of -1 .

Pro Tips

Common Errors (and the fix)

Frequently Asked Questions

Mini-Challenge: Vote Tally

Count votes per colour with a dictionary, then find the winner. The outline is in the comments — fill in the body.

🎉 Lesson Complete

Practice quiz

What does a Dictionary<TKey, TValue> map?

  • Positions to values
  • Unique keys to values
  • Values to keys only
  • Indexes to a sorted list

Answer: Unique keys to values. A Dictionary maps a unique key to a value, and finds the value by key almost instantly.

What happens if you call Add with a key that already exists?

  • It overwrites the value silently
  • It returns false
  • It throws ArgumentException
  • It adds a duplicate entry

Answer: It throws ArgumentException. Add with a duplicate key throws ArgumentException; use the indexer dict[key] = value to overwrite instead.

What does the indexer dict[key] = value do when the key already exists?

  • Throws an exception
  • Overwrites the existing value silently
  • Ignores the assignment
  • Adds a second entry

Answer: Overwrites the existing value silently. Assigning with the indexer overwrites an existing key's value silently — handy when overwriting is intended.

What happens when you read a missing key with the indexer dict[key]?

  • Returns null
  • Returns the type's default
  • Throws KeyNotFoundException
  • Returns false

Answer: Throws KeyNotFoundException. Reading a key that isn't present with the indexer throws KeyNotFoundException — use TryGetValue or ContainsKey instead.

Why is TryGetValue preferred over ContainsKey + indexer?

  • It sorts the dictionary
  • It checks and fetches in a single lookup
  • It never returns false
  • It allows duplicate keys

Answer: It checks and fetches in a single lookup. TryGetValue does the existence check and the fetch in one lookup, so it's faster and cleaner than checking with ContainsKey then reading.

When a key is absent, what does TryGetValue do to the out parameter?

  • Leaves it unassigned
  • Sets it to the type's default and returns false
  • Throws
  • Sets it to null always

Answer: Sets it to the type's default and returns false. TryGetValue returns false and sets the out value to the type's default (e.g. 0 for int) — it never throws.

Does a standard Dictionary guarantee iteration order?

  • Yes, insertion order
  • Yes, sorted by key
  • No, it makes no promise about order
  • Only for string keys

Answer: No, it makes no promise about order. A standard Dictionary makes no promise about iteration order; use SortedDictionary for keys sorted by key.

What does GetValueOrDefault("m", -1) return when key "m" is absent?

  • 0
  • null
  • -1
  • Throws KeyNotFoundException

Answer: -1. GetValueOrDefault returns the supplied fallback (-1 here) for a missing key, never throwing.

Which one-liner implements the counting pattern with GetValueOrDefault?

counts[c] = counts.GetValueOrDefault(c) + 1; starts missing keys at 0 then increments — the whole tally pattern in one line.

What type do you get when you iterate a Dictionary with foreach?

  • A KeyValuePair<TKey, TValue> per entry
  • Just the keys
  • Just the values
  • A tuple of indexes

Answer: A KeyValuePair<TKey, TValue> per entry. Iterating a Dictionary yields a KeyValuePair<TKey, TValue> for each entry, exposing .Key and .Value.

Continue this course