A missing key often means "none yet"
Think of a shop that counts its fruit. If there are no plums in stock, the shop has zero plums, and the dictionary may simply have no "plums" key. But stock["plums"] cannot say zero. Reading a key that is not in a Dictionary throws a KeyNotFoundException.
The method GetValueOrDefault(key, defaultValue) solves this. It returns the key's value when the key is there, and the default you pass when it is not.
Dictionary<string, int> stock = new Dictionary<string, int>();
stock["apples"] = 5;
Console.WriteLine(stock.GetValueOrDefault("apples", 0));
Console.WriteLine(stock.GetValueOrDefault("plums", 0));
Console.WriteLine(stock.Count);
5
0
1
The last line matters: reading with GetValueOrDefault does not add the key. After asking for plums, stock still has one key. In a file of your own, add using System; and using System.Collections.Generic;.
The longer way to write it
The method replaces this if:
int plums = 0;
if (stock.ContainsKey("plums")) {
plums = stock["plums"];
}
Both versions give the same plums. The method says it in one line, and the dictionary is searched once.
A common use: counting
Because the default stands in for "none yet", GetValueOrDefault is the natural tool for counting. To count how often each word appears, read the old count, add one, and store it back:
Dictionary<string, int> counts = new Dictionary<string, int>();
foreach (string w in new[] {"red", "blue", "red"}) {
counts[w] = counts.GetValueOrDefault(w, 0) + 1;
}
A word seen for the first time starts from 0 and becomes 1. At the end, counts holds blue with 1 and red with 2.
The exercise, step by step
stock holds 5 apples and 2 pears, and the code already prints the pears line. There are no plums.
- Read the plums with a default. Call
stock.GetValueOrDefault("plums", 0)and store the result in anintnamedplums. The key is missing, soplumsis 0. - Print the plums line. Copy the pears line and use
plumsin place ofpears.
Dictionary<string, int> stock = new Dictionary<string, int>();
stock["apples"] = 5;
stock["pears"] = 2;
int pears = stock["pears"];
Console.WriteLine("We have " + pears + " pears");
int plums = stock.GetValueOrDefault("plums", 0);
Console.WriteLine("We have " + plums + " plums");
We have 2 pears
We have 0 plums
The pears line reads with stock["pears"] because that key exists. The plums line needs the safe version.
Details and traps
The default has to fit the value type. For a Dictionary<string, int> it is an int, and for a Dictionary<string, string> it is a string, such as "". The compiler checks this, so a mismatched default does not build.
- The default is yours to pick. Zero suits counts. For a different job, pass something else:
stock.GetValueOrDefault("plums", -1)gives -1, which can mean "not tracked". - Leaving the default out.
GetValueOrDefault("plums")uses the default for the value type: 0 forint, andnullfor a string value. Anullcan cause aNullReferenceExceptionlater, so give a default when you can. - It only reads. To save a result, assign it:
stock["plums"] = 3;. - The default is not stored. A later
stock.ContainsKey("plums")is stillfalse. - A stored zero looks like a missing key. If a key is present with the value 0, the read also gives 0. Use
ContainsKeywhen that difference matters.
Key takeaways
d.GetValueOrDefault(key, 0)gives the value, or 0 for a missing key.- It never throws and never adds the key.
- Plain
d[key]throws aKeyNotFoundExceptionfor a missing key. - It is a short form of
ContainsKeyplus a read.
