Dictionaries in C#

A Dictionary<TKey, TValue> stores values under unique keys, so you can look one up by its label instead of its position.

Apprentice · C# · Updated

After this lesson you can

  • Store and look up values by key in a Dictionary<TKey, TValue>
  • Loop through a dictionary's keys and values

Key takeaways

  • A dictionary stores values under keys, so you look a value up by its key, as in prices["bagel"], instead of by its position.
  • Each key appears only once: setting a key that's already there replaces its value, while Add stops the program with an ArgumentException.
  • Reading a key that isn't there stops the program with a KeyNotFoundException, so check with ContainsKey or use TryGetValue.
  • foreach gives each pair as a KeyValuePair with a .Key and a .Value; .Keys and .Values loop over just one side.
  • A dictionary doesn't promise any order. When you need the keys in order, use a SortedDictionary<TKey, TValue>, which keeps them sorted.

A list finds items by their position: the first, the third. Often you want to find something by a label instead: the price of "coffee", the mascot of "Georgia", the phone number of "Ana". A dictionary stores values in key/value pairs: the key is the label, and the value is what it labels.

Creating a dictionary

The two types in angle brackets are the key's type and the value's type:

Dictionary<string, decimal> prices = new Dictionary<string, decimal>();
prices["coffee"] = 3.50m;
prices["bagel"] = 2.25m;
prices["juice"] = 4.00m;

Console.WriteLine(prices["bagel"]);
Console.WriteLine(prices.Count);
2.25
3

Dictionary<string, decimal> reads as "a dictionary from strings to decimals". You set and read values with the key in square brackets, where a list would take an index.

You can also fill it as you create it:

Dictionary<string, string> mascots = new Dictionary<string, string>
{
    ["Georgia"] = "Bulldogs",
    ["Alabama"] = "Crimson Tide",
    ["Ohio State"] = "Buckeyes"
};

Console.WriteLine(mascots["Ohio State"]);
Buckeyes

Keys are unique

Each key appears at most once, like a word in a real dictionary. Setting a key that's already there replaces its value:

Dictionary<string, decimal> prices = new Dictionary<string, decimal>();
prices["coffee"] = 3.50m;
prices["coffee"] = 3.75m;

Console.WriteLine(quot;{prices.Count} item, coffee costs {prices["coffee"]}");
1 item, coffee costs 3.75

Add(key, value) also adds a pair, but it stops the program with an ArgumentException if the key is already there. Use it when a repeated key would be a mistake.

Looking up safely

Reading a key that isn't in the dictionary stops the program with a KeyNotFoundException. Check first with ContainsKey, or use TryGetValue, which does the check and the lookup in one go:

Dictionary<string, decimal> prices = new Dictionary<string, decimal>
{
    ["coffee"] = 3.50m,
    ["bagel"] = 2.25m
};

Console.WriteLine(prices.ContainsKey("tea"));

if (prices.TryGetValue("bagel", out decimal price))
{
    Console.WriteLine(quot;A bagel is {price:C}");
}

if (!prices.TryGetValue("tea", out decimal teaPrice))
{
    Console.WriteLine("We don't sell tea.");
}
False
A bagel is $2.25
We don't sell tea.

TryGetValue returns true and fills the out variable when the key is there, the same shape as int.TryParse.

Removing

Remove(key) takes a pair out, and returns true if the key was there:

Dictionary<string, int> stock = new Dictionary<string, int> { ["apples"] = 12, ["pears"] = 0 };
stock.Remove("pears");
Console.WriteLine(stock.Count);
1

Looping through a dictionary

foreach visits every pair. Each one is a KeyValuePair, with a .Key and a .Value:

Dictionary<string, int> wins = new Dictionary<string, int>
{
    ["Georgia"] = 12,
    ["Alabama"] = 10,
    ["Ohio State"] = 11
};

foreach (KeyValuePair<string, int> team in wins)
{
    Console.WriteLine(quot;{team.Key}: {team.Value}");
}

int totalWins = 0;
foreach (int teamWins in wins.Values)
{
    totalWins += teamWins;
}
Console.WriteLine(quot;Total: {totalWins}");
Georgia: 12
Alabama: 10
Ohio State: 11
Total: 33

wins.Keys and wins.Values let you loop over just the keys or just the values.

A dictionary doesn't promise any order. Pairs often come out in the order they were added, but don't count on it. When the order matters, use a SortedDictionary<TKey, TValue>, which keeps its keys sorted.

Counting with a dictionary

A classic use: count how many times each thing appears.

string[] votes = { "pizza", "tacos", "pizza", "sushi", "pizza", "tacos" };
Dictionary<string, int> counts = new Dictionary<string, int>();

foreach (string vote in votes)
{
    if (counts.ContainsKey(vote))
    {
        counts[vote]++;
    }
    else
    {
        counts[vote] = 1;
    }
}

Console.WriteLine(quot;pizza: {counts["pizza"]}, tacos: {counts["tacos"]}, sushi: {counts["sushi"]}");
pizza: 3, tacos: 2, sushi: 1

Check yourself

2 questions to try on the lesson page.

So what

Whenever you find yourself searching a list for "the one with this name", a dictionary is the better tool: it goes straight to the value by its key.

Key terms

Cheat sheets