Start learning free

LESSON 221 OF 667 · LOOPS WITH STRINGS, ARRAYS & DICTIONARIES

Looping Over a Dictionary in C++ with unordered_map

Lesson Read the full explanation

TL ; DR:

A range-based for loop over an unordered_map visits every entry. The [fruit, amount] part splits each one into its key and its value.


unordered_map<string, int> stock;
stock["apples"] = 5;
stock["pears"] = 2;

for (auto& [fruit, amount] : stock) {
    cout << fruit << " " << amount << endl;
}

// pears 2
// apples 5   (in any order)


Full lesson:

A loop can visit every entry of a map, one at a time. The loop body runs once per key.

Each entry of the map is a pair of a key and its value. [fruit, amount] gives both parts a name.

auto lets C++ work out the types. The & visits each entry where it is, without a copy.

Older code writes entry.first for the key and entry.second for the value. It's the same pair.

The order: an unordered_map has no fixed order. That's what "unordered" means. A total or a count comes out the same in any order. Those are safe answers.

Watch out: don't add keys inside the loop. Even reading stock[key] with a new key adds that key.


Your task

A game keeps each player's points in scores. The variables total and count start at 0.

Loop over scores. Add every player's points to total. Count the players with 10 points or more in count.

The code at the bottom prints both.

Expected output:

43
2
STEP 1 OF 3
    Ctrl + Enter to check

    C++ · LOOPS WITH STRINGS, ARRAYS & DICTIONARIES

    Looping Over Dictionaries in C++, explained

    What the loop does

    An unordered_map stores key and value pairs. A range-based for loop visits every entry once, and the body runs once per key. In this lesson the map is scores: each key is a player's name and each value is that player's points.

    unordered_map<string, int> stock;
    stock["apples"] = 5;
    stock["pears"] = 2;
    
    for (auto& [fruit, amount] : stock) {
        cout << fruit << " " << amount << endl;
    }
    

    This prints the two entries in an order the program doesn't choose. Both of these are possible:

    pears 2
    apples 5
    

    Reading the loop header

    • [fruit, amount] is a structured binding. Each entry is a pair, and the binding gives its two parts names: fruit is the key and amount is the value.
    • auto lets the compiler work out the types, here string and int.
    • & makes the names refer to the entry inside the map instead of to a copy.

    Older code names the entry and uses its two members: entry.first is the key and entry.second is the value. It is the same pair, only with different names.

    What the & changes

    With &, assigning to the value changes the map. Without it, the loop works on a copy of each entry, and the map stays as it was. Starting from the scores 12, 7, 15 and 9 (total 43), a loop that adds 1 to every player's points gives these totals:

    • with auto& [name, points], the map's total becomes 47;
    • with auto [name, points], the map's total stays 43, because only the copies changed.

    When the loop only reads, the & is still the better habit. It avoids copying a string key for every entry.

    Two traps

    • The order is not fixed. That is what "unordered" means. Code that only adds things up or counts is safe, because the total and the count are the same in any order. Code that needs "the first one" or a sorted listing must not rely on this loop's order.
    • Don't add keys inside the loop. Even reading stock[key] with a key that is missing adds that key with the value 0. Starting with 4 players, reading scores["Zed"] once makes the size 5. scores.count("Zed") asks without adding anything.

    The lesson's task

    The map holds Ana 12, Ben 7, Cleo 15 and Dan 9. The task is to add every player's points to total and to count, in count, the players with 10 points or more.

    1. Write the loop with auto& [name, points] over scores.
    2. Inside it, add points to total.
    3. Still inside, if points is at least 10, add 1 to count.
    unordered_map<string, int> scores;
    scores["Ana"] = 12;
    scores["Ben"] = 7;
    scores["Cleo"] = 15;
    scores["Dan"] = 9;
    int total = 0;
    int count = 0;
    
    for (auto& [name, points] : scores) {
        total += points;
        if (points >= 10) {
            count += 1;
        }
    }
    
    cout << total << endl;
    cout << count << endl;
    

    It prints:

    43
    2
    

    The total is 12 + 7 + 15 + 9 = 43, and only Ana and Cleo have 10 or more. The variable name is never used in the body. That is fine here, because the binding is there to take the entry apart.

    Key takeaways

    • for (auto& [key, value] : map) visits every entry once.
    • Use & to avoid copies, and to change values in place.
    • The order is unspecified, so totals and counts are safe answers.
    • Don't add keys while looping, and remember that map[key] adds a missing key.
    Keep going with C++500+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free