Start learning free

LESSON 226 OF 671 · LOOPS WITH STRINGS, ARRAYS & DICTIONARIES

Looping Over a Map in Go: range and Random Order

Lesson Read the full explanation

TL ; DR:

A for loop with range visits every key of a map, together with its value.


stock := map[string]int{"apples": 5, "pears": 2}

for fruit, amount := range stock {
    fmt.Println(fruit, amount)
}

// 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.

range hands the loop each key together with its value. The key comes first, then the value.

Leave out the second variable to get only the keys.

for fruit := range stock {
    fmt.Println(fruit, stock[fruit])
}

Don't need the key? Write _ in its place, as in for _, amount := range stock. Go refuses to compile a variable you never use.

The order: Go visits a map in a random order, on purpose. Two runs of the same program can print different orders. A total or a count comes out the same in any order. Those are safe answers.


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 loop needs only the points, not the names. The code at the bottom prints both.

Expected output:

43
2
STEP 1 OF 3
    Ctrl + Enter to check

    GO · LOOPS WITH STRINGS, ARRAYS & DICTIONARIES

    Looping Over Dictionaries in Go, explained

    What a range loop over a map does

    A for loop with range visits every entry of a map once. On each turn it hands you the key first and the value second:

    stock := map[string]int{"apples": 5, "pears": 2}
    
    for fruit, amount := range stock {
        fmt.Println(fruit, amount)
    }
    

    This prints both entries, apples 5 and pears 2, but not in a promised order.

    Keys only, or values only

    Write one variable and range gives only the keys. You can still read each value by indexing the map:

    for fruit := range stock {
        fmt.Println(fruit, stock[fruit])
    }
    

    If you need only the values, put the blank identifier _ where the key would go: for _, amount := range stock. Go refuses to compile a variable that is declared and never used, so _ is how you say "I don't need this one".

    The order is random on purpose

    Go does not visit a map in insertion order or in sorted order. It picks the starting point at random, so two runs of the same program can print the entries in different orders. Don't write code that depends on which key comes first.

    Some answers do not depend on the order. A total, a count, or a "does any entry match" check come out the same however the entries are visited. When you do need a fixed order, collect the keys into a slice, sort it with the sort package, and loop over the slice. In a file of your own, that looks like this (it needs import "sort"):

    keys := []string{}
    for k := range stock {
        keys = append(keys, k)
    }
    sort.Strings(keys)
    fmt.Println(keys)
    

    This prints [apples pears] every time.

    The lesson's task

    The map scores holds each player's points. The task is to add every player's points to total and to count the players with 10 points or more in count. Both answers are order-independent, so the random order is harmless. The names are not needed, so the key goes into _.

    1. Write for _, points := range scores { and close it with }.
    2. Inside, add points to total.
    3. Still inside, if points is at least 10, add 1 to count.
    scores := map[string]int{"Ana": 12, "Ben": 7, "Cleo": 15, "Dan": 9}
    total := 0
    count := 0
    
    for _, points := range scores {
        total += points
        if points >= 10 {
            count += 1
        }
    }
    
    fmt.Println(total)
    fmt.Println(count)
    

    The output is:

    43
    2
    

    The points are 12, 7, 15 and 9, which add up to 43. Ana (12) and Cleo (15) have 10 or more, so the count is 2.

    Because a map is only ever visited as a whole, a loop over one is a natural fit for summaries: how many entries pass a test, what they add up to, or which is the largest. Each of those results is the same however the entries are ordered, which is why the lesson asks for a total and a count and nothing that prints names.

    Common mistakes

    • Leaving the key as a named variable. for name, points := range scores does not compile when name is never used. Use _.
    • Expecting a fixed order. Printing inside the loop can give a different order on each run. Sort the keys first if the order matters.
    • Putting the if outside the loop. Then it sees only the last points value, not each one in turn.

    Key takeaways

    • for key, value := range m visits every entry once; one variable gives only the keys.
    • Use _ for the part you don't need.
    • The visiting order is random, so use loops over maps for totals, counts and checks, or sort the keys first.
    Keep going with Go500+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free