std::map
A vector finds values by position: element 0, element 1. A std::map finds them by a key you choose: a name, a word, a product code. Each key appears once, with one value.
Keys and values
#include <iostream>
#include <map>
#include <string>
using namespace std;
int main() {
map<string, int> ages; // keys are strings, values are ints
ages["Leo"] = 31;
ages["Asha"] = 24;
ages["Mei"] = 28;
cout << "Asha is " << ages["Asha"] << endl;
ages["Asha"] = 25; // the same key again: the value is replaced
for (const auto& [name, age] : ages)
cout << name << ": " << age << endl;
cout << ages.size() << " people" << endl;
return 0;
}Asha is 24
Asha: 25
Leo: 31
Mei: 28
3 peoplemap<string, int>maps string keys to int values.ages["Leo"] = 31adds the key, or updates it if it's already there.- A map keeps its keys sorted, so the loop visits Asha, Leo, Mei in alphabetical order, whatever order they were added in.
const auto& [name, age]unpacks each entry into its key and value. This is a structured binding, from C++17.
Looking up safely
#include <iostream>
#include <map>
#include <stdexcept>
#include <string>
using namespace std;
int main() {
map<string, double> prices = {{"apple", 0.5}, {"bread", 2.25}, {"milk", 1.2}};
auto it = prices.find("cheese");
if (it == prices.end()) cout << "No cheese on the list" << endl;
else cout << "Cheese costs " << it->second << endl;
cout << prices.count("milk") << " " << prices.count("cheese") << endl;
cout << prices["cheese"] << endl; // [] quietly adds cheese, priced 0
cout << prices.size() << " items now" << endl;
prices.erase("cheese");
cout << prices.size() << " items after erase" << endl;
try {
prices.at("cake");
} catch (const out_of_range&) {
cout << "at() throws for a missing key" << endl;
}
return 0;
}No cheese on the list
1 0
0
4 items now
3 items after erase
at() throws for a missing keyThere are three ways to ask about a key, and they behave differently:
find(key)returns an iterator to the entry, orend()if there isn't one.it->firstis the key andit->secondthe value.count(key)is 1 if the key exists and 0 if not. (C++20 addscontains, but this course targets C++17.)map[key]creates the entry, with a zero value, when the key is missing. That's handy for counting and a trap for checking.
Counting words
This example's input is the cat and the hat and the bat:
#include <iostream>
#include <map>
#include <string>
using namespace std;
int main() {
map<string, int> counts;
string word;
while (cin >> word) counts[word]++; // a new word starts at 0, then becomes 1
string top;
for (const auto& [w, n] : counts) {
cout << w << " " << n << endl;
if (top.empty() || n > counts[top]) top = w;
}
cout << "Most common: " << top << endl;
return 0;
}and 2
bat 1
cat 1
hat 1
the 3
Most common: theThis is where [] creating missing entries pays off: counts[word]++ works for words seen before and words seen for the first time. Counting things by key is one of the most common jobs a map does.
unordered_map
#include <iostream>
#include <string>
#include <unordered_map>
using namespace std;
int main() {
unordered_map<char, int> freq;
for (char c : string("mississippi")) freq[c]++;
cout << "s: " << freq['s'] << ", i: " << freq['i'] << ", p: " << freq['p'] << endl;
return 0;
}s: 4, i: 4, p: 2unordered_map works the same way but stores keys in a hash table instead of in sorted order. Lookups are usually faster, especially for big maps, but looping over it visits keys in no particular order. Use map when you want sorted keys, and unordered_map when you only look things up.