.NET Academy

Dictionaries and sets

Look things up by key instantly with Dictionary, and track unique items with HashSet.

12 min read

You will learn

  • Store and retrieve values by key with Dictionary<TKey, TValue>
  • Read safely with TryGetValue and ContainsKey
  • Count and group data with a dictionary
  • Use HashSet<T> for uniqueness and set operations

Lookup by key

A list answers "what's at position 3?". Often you need to ask "what's the price of coffee?" or "which user has the id 42?". Searching a list for that means checking every item. A dictionary maps keys to values and finds any key almost instantly.

var prices = new Dictionary<string, decimal>
{
    ["coffee"] = 3.50m,
    ["tea"] = 2.80m,
};
 
prices["juice"] = 4.20m;                 // add (or overwrite)
Console.WriteLine(prices["coffee"]);     // 3.50
Console.WriteLine(prices.Count);         // 3

Keys are unique; values can repeat. Keys and values can be any type: Dictionary<int, User>, Dictionary<string, List<Order>>…

Reading safely

Reading a missing key with the indexer throws KeyNotFoundException. When a key might be absent:

if (prices.TryGetValue("water", out decimal price))
    Console.WriteLine(price);
else
    Console.WriteLine("Not on the menu");
 
decimal p = prices.GetValueOrDefault("water");        // 0 if missing
decimal q = prices.GetValueOrDefault("water", 1.00m); // custom fallback
 
bool hasTea = prices.ContainsKey("tea");

Adding, updating, removing

OperationEffect
dict[key] = valueAdd, or overwrite if the key exists
dict.Add(key, value)Add — throws if the key exists
dict.TryAdd(key, value)Add only if missing (returns bool)
dict.Remove(key)Remove (returns bool)

Looping

Each entry is a KeyValuePair<TKey, TValue>, which you can deconstruct:

foreach (var (item, cost) in prices)
{
    Console.WriteLine($"{item}: {cost:F2}");
}
 
foreach (string key in prices.Keys) { ... }
foreach (decimal value in prices.Values) { ... }

Note

Dictionary doesn't promise any particular order. If you need keys sorted, use SortedDictionary<TKey, TValue> or sort when displaying.

The counting pattern

Counting occurrences is one of the most common dictionary tasks:

var counts = new Dictionary<char, int>();
foreach (char c in "mississippi")
{
    counts[c] = counts.GetValueOrDefault(c) + 1;
}
// m:1, i:4, s:4, p:2

The same shape works for grouping: Dictionary<string, List<Order>> ordersByCustomer.

How it's so fast: hashing

A dictionary calls GetHashCode() on each key to compute which internal "bucket" it belongs to, then jumps straight there. Lookups take roughly the same time with 10 entries or 10 million — O(1) on average, versus O(n) for searching a list.

That's also why keys must not change after being added, and why types used as keys need sensible Equals and GetHashCode — which records, strings and numbers already have.

HashSet: just the keys

Sometimes you only care whether something is in a collection. A HashSet<T> stores unique items with the same fast lookup:

var visited = new HashSet<string>();
visited.Add("Paris");
visited.Add("Rome");
bool added = visited.Add("Paris");      // false — already there
 
Console.WriteLine(visited.Contains("Rome"));   // true, and fast
Console.WriteLine(visited.Count);              // 2

Sets support mathematical set operations:

var a = new HashSet<int> { 1, 2, 3 };
var b = new HashSet<int> { 2, 3, 4 };
 
a.IntersectWith(b);    // a = { 2, 3 }     — in both
// a.UnionWith(b);     //   { 1, 2, 3, 4 } — in either
// a.ExceptWith(b);    //   { 1 }          — in a but not b

Removing duplicates from a list is a one-liner: var unique = new HashSet<string>(names);

Try it

Program.cs
Loading editor…

C# runtime not loaded

Key takeaways

  • Dictionary<TKey, TValue> maps unique keys to values with near-instant lookup.
  • Use TryGetValue / GetValueOrDefault when a key may be missing; the indexer throws.
  • dict[key] = value adds or overwrites; GetValueOrDefault(key) + 1 is the counting idiom.
  • HashSet<T> stores unique items and supports fast Contains and set operations.

Exercise

WordCounts counts how often each word appears (case-insensitive, words separated by spaces). MostFrequent returns the most common word. HasDuplicates reports whether any number appears twice. CommonCount returns how many DISTINCT numbers appear in both arrays.

Program.cs
Loading editor…

C# runtime not loaded

Hint 1

WordCounts: split with text.ToLower().Split(' ', StringSplitOptions.RemoveEmptyEntries), then counts[word] = counts.GetValueOrDefault(word) + 1.

Hint 2

MostFrequent: build the counts, then loop over the pairs (foreach (var (word, count) in counts)) keeping the best.

Hint 3

HashSet.Add returns false when the item is already there — perfect for HasDuplicates. For CommonCount, look at IntersectWith.

Show solution
var counts = WordCounts("the cat and the hat");
Console.WriteLine(counts.Count);

Dictionary<string, int> WordCounts(string text)
{
    var counts = new Dictionary<string, int>();
    foreach (var word in text.ToLower().Split(' ', StringSplitOptions.RemoveEmptyEntries))
    {
        counts[word] = counts.GetValueOrDefault(word) + 1;
    }
    return counts;
}

string MostFrequent(string text)
{
    string best = "";
    int bestCount = 0;
    foreach (var (word, count) in WordCounts(text))
    {
        if (count > bestCount)
        {
            best = word;
            bestCount = count;
        }
    }
    return best;
}

bool HasDuplicates(int[] numbers)
{
    var seen = new HashSet<int>();
    foreach (var n in numbers)
    {
        if (!seen.Add(n)) return true;
    }
    return false;
}

int CommonCount(int[] a, int[] b)
{
    var set = new HashSet<int>(a);
    set.IntersectWith(b);
    return set.Count;
}

Quiz

4 questions · 3 correct to pass
  1. 1.What happens when you read `dict["missing"]` for a key that isn't there?

  2. 2.What does `dict["a"] = 5;` do if "a" already exists?

  3. 3.Why are dictionary lookups fast even with millions of entries?

  4. 4.What does `new HashSet<int> { 1, 2, 2, 3 }.Count` return?

To complete this lesson

  • ○ Solve the exercise
  • ○ Pass the quiz (3/4 correct)