Asking whether a key is there
An unordered_map stores keys with values. Before you use a key, you often need to know whether the map has it. The method for that is count(key). A map holds each key at most once, so count returns only two answers: 1 when the key is there, and 0 when it isn't.
unordered_map<string, string> capitals = {{"France", "Paris"}, {"Japan", "Tokyo"}};
if (capitals.count("Japan") > 0) {
cout << capitals["Japan"] << endl; // Tokyo
}
if (capitals.count("Spain") == 0) {
cout << "No Spain" << endl; // No Spain
}
Use count(key) > 0 for "the key exists" and count(key) == 0 for "the key is missing". Newer C++ versions also have a contains method, but C++17, which this course uses, does not, so write it with count.
Do not check with []
The square brackets look like a natural way to test, but they change the map. Reading capitals["Spain"] on a missing key adds "Spain" with an empty string as its value. The map then has three entries, and capitals.count("Spain") is 1. For an unordered_map<string, int>, the added value is 0.
So always ask with count first, and read with [] only inside the check.
Keys only
- A value is not a key.
capitals.count("Paris")is 0, because"Paris"is a value.countlooks only at keys. - Exact match. Upper and lower case count as different letters, so
capitals.count("japan")is 0. - Not an error. Asking about a missing key just returns 0. Nothing crashes and nothing is added.
The exercise: pets and kinds
The map pets goes from a pet's name to its kind: Rex is a dog, Tom is a cat and Polly is a parrot. The task has two checks:
- If
pets.count("Tom")is greater than 0, printTom is afollowed bypets["Tom"]. Reading with[]is safe here because the check just proved the key exists. - If
pets.count("cat")is 0, printcat is not a key. The word"cat"does appear in the map, but only as Tom's kind, which is a value. So the count is 0.
unordered_map<string, string> pets = {{"Rex", "dog"}, {"Tom", "cat"}, {"Polly", "parrot"}};
if (pets.count("Tom") > 0) {
cout << "Tom is a " << pets["Tom"] << endl;
}
if (pets.count("cat") == 0) {
cout << "cat is not a key" << endl;
}
The output is:
Tom is a cat
cat is not a key
Notice the space at the end of "Tom is a ". Without it, the kind would run into the word before it.
Two ways to get it wrong
Suppose you wrote the first check as if (pets["Tom"] != ""). For Tom it works, but for a name that is not in the map it would add that name as a new key with an empty kind, and the map would grow without any warning. The second slip is searching for a value as if it were a key. If you want to know whether any pet is a cat, count("cat") cannot tell you, because it only looks at the names.
Both mistakes come from forgetting what a map is for: you look something up by key, and the key must be exactly the one you stored.
Key takeaways
m.count(key)is 1 when the key is there and 0 when it isn't.countchecks keys only, and the match is exact.- Never test with
m[key]: on a missing key, it adds the key. - Read
m[key]only aftercounthas said the key exists.
