Go

Why is map iteration order random, and how do you iterate deterministically?

Question 57MediumGo 1.22 to 1.25

The spec says iteration order is unspecified. The runtime goes further and deliberately randomizes it: each range starts at a random position (in the classic map, a random bucket and offset). The reasons are:

  • Stop people depending on it. Before Go 1.0, programs relied on insertion-like order that broke when the implementation changed.
  • Allow implementation freedom. Growth, evacuation, and the Swiss-table rewrite could not keep any stable order anyway.
m := map[string]int{"b": 2, "a": 1, "c": 3}

for k := range m { fmt.Print(k) } // e.g. "bca", differs between runs

// Deterministic: sort the keys (Go 1.23 iterators)
for _, k := range slices.Sorted(maps.Keys(m)) {
	fmt.Println(k, m[k])
}

// fmt prints maps sorted by key since Go 1.12
fmt.Println(m) // map[a:1 b:2 c:3]

Gotchas:

  • fmt.Println(m) looks ordered, which hides the problem in debug output.
  • Golden-file tests and hashes computed over map iteration are flaky.
  • encoding/json sorts map keys, but gob does not promise any order.

If you need insertion order, keep a []K next to the map, or use an ordered-map type (a map plus a linked list).

More on Arrays, Slices, Maps & Strings

All 37 Arrays, Slices, Maps & Strings questions