Skip to content
Theory · Maps · lesson 4 of 9

Iterating over a map

In a real phone book the names are in alphabetical order. Our map book works differently: its entries have no order. That does not stop you from finding a number by name. It only gets in the way of someone who reads the whole book and expects the entries to come in order.

A range loop visits every pair of a map, but not necessarily in the order they were written. If you print the pairs in a loop, the order of the lines can change from one run to the next. A result that does not depend on the order is always the same, such as a sum:

GO
package main

import "fmt"

func main() {
    stock := map[string]int{"pear": 3, "plum": 5, "kiwi": 2}
    total := 0
    for _, n := range stock {
        total += n
    }
    fmt.Println(total) // 10
}

The loop takes the pairs in some order, but each value goes into the sum exactly once. So in any order total is 3 + 5 + 2, and the program always prints 10.

Three forms of the loop

A range loop over a map comes in three forms, depending on what you need from each pair.

Key and value

In for k, v := range m, the variable k gets the key and v gets the value. Use this form when you need both, for example to print the pairs.

Keys only

If the values are not needed, write for k := range m: you leave out the second variable. This is how keys are collected into a slice, as in the section on iterating by key below.

Values only

If the keys are not needed, put _ in their place: for _, v := range m. That is how the sum in the first example works. The key cannot be left out the way the value can: the first variable of range always gets the key.

The order is not set

The language does not set the order in which the pairs come. Moreover, Go changes it on purpose: each pass over a map starts at a random place. So two runs of a program, and even two loops in a row in one program, can visit the pairs differently.

This is deliberate, so that code does not depend on how a map is built inside. These do not depend on the order, for example:

  • the sum of the values;
  • the number of pairs;
  • the largest value.

Interviewers like to ask: "In what order does range visit a map?" The answer: the order is not set, and Go makes it random on purpose. If you need a stable order, you set it up yourself, as the next section shows.

Iterating by key

When the order matters, collect the keys into a slice and sort them with the slices.Sort function from the slices package (import "slices"). The loop then goes over the slice, and the values are read from the map by key:

GO
stock := map[string]int{"pear": 3, "plum": 5, "kiwi": 2}
keys := make([]string, 0, len(stock))
for k := range stock {
    keys = append(keys, k)
}
slices.Sort(keys)
fmt.Println(keys) // [kiwi pear plum]
for _, k := range keys {
    fmt.Print(k, ":", stock[k], " ") // kiwi:2 pear:3 plum:5
}

Let's walk through the example line by line:

  1. make([]string, 0, len(stock)) creates an empty slice with room for every key.
  2. The first loop puts the keys into it in a random order.
  3. slices.Sort(keys) puts them in alphabetical order, and Println prints [kiwi pear plum].
  4. The second loop goes over the sorted slice and reads each key's value from the map.

What slices.Sort does:

  • it reorders the elements of the slice itself and returns nothing;
  • it puts strings in alphabetical order, with capital letters before lowercase ones;
  • it puts numbers in ascending order;
  • it leaves the map itself alone: only the slice of its keys is sorted.

For a slice of strings, sort.Strings(keys) from the sort package does the same.

Printing a whole map

The call fmt.Println(stock) prints map[kiwi:2 pear:3 plum:5]: the fmt package sorts the keys itself before printing. A range loop does not.

Common mistake

The keys are the numbers 1, 2 and 3, and the loop is expected to visit the pairs in ascending order:

GO
names := map[int]string{1: "pear", 2: "plum", 3: "kiwi"}
for k, v := range names { // ✗
    fmt.Println(k, v)
}

The lines come out in any order, and it can differ from run to run. On a small map, the order often matches the expected one, so the mistake is hard to notice. A program that passed a check on one run fails it on the next. Collect the keys into a slice and sort them, as shown above.

Key points

  • range over a map yields the pairs in no set order, and Go makes the order random on purpose.
  • A sum, the number of pairs or the maximum do not depend on the order and always come out the same.
  • For a stable order, collect the keys into a slice, sort it with slices.Sort and read the values by key.

Subscribe to take the course

The course is free. Sign in with Telegram and subscribe to the channel to open every lesson.

Sign in another way