Iterating a Map in Go
Maps in Go are unordered: each program run randomises the iteration order to discourage code that relies on it. This snippet shows the basic `for key, value := range m` form, the comma-ok idiom for safe lookup, and the canonical pattern for iterating in sorted order. Internalise these three and you avoid the most common map bugs.
1,193 views
21
package main
import (
"fmt"
"sort"
)
func main() {
ages := map[string]int{
"ada": 36,
"linus": 54,
"margaret": 88,
}
// Order is randomised each run; do NOT rely on it.
for name, age := range ages {
fmt.Printf("%s = %d\n", name, age)
}
// Key-only:
for k := range ages {
_ = k
}
fmt.Println("size =", len(ages))
_ = sort.Strings // keep import alive; used in the next accordion
}for k, v := range m iterates over key/value pairs; drop , v if you only want keys, drop k, if you only want values (or use for _, v := range m). The runtime deliberately randomises the order each iteration to keep maps a black box, so any code that depends on order is buggy by definition. len(m) is O(1) and reports the current number of entries. Modifying the map during iteration is allowed but visiting newly added keys is unspecified; deleting the current key is safe.
package main
import "fmt"
func main() {
ages := map[string]int{"ada": 36}
// Single value: returns the zero value when missing (0 for int, "" for string).
age := ages["missing"]
fmt.Printf("missing => %d (zero value)\n", age)
// Comma-ok: distinguishes "present and zero" from "missing".
if v, ok := ages["ada"]; ok {
fmt.Printf("ada present, age=%d\n", v)
}
if _, ok := ages["linus"]; !ok {
fmt.Println("linus is missing")
}
}v := m[key] returns the zero value of the value type when the key is missing, which is convenient but ambiguous: you cannot tell whether the value was genuinely zero or absent. The comma-ok form v, ok := m[key] returns a second boolean that is true if and only if the key exists. Use comma-ok any time the zero value is meaningful (counts that can legitimately be 0, booleans where false is data) or when you need to react differently to absence. This is the same idiom used for type assertions and channel receives.
package main
import (
"fmt"
"sort"
)
func main() {
ages := map[string]int{
"ada": 36,
"linus": 54,
"margaret": 88,
}
keys := make([]string, 0, len(ages))
for k := range ages {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
fmt.Printf("%s = %d\n", k, ages[k])
}
}Go does not have a sorted map in the standard library. The canonical pattern is to collect the keys into a slice, sort the slice, then iterate the slice and look up each value. The cost is O(n log n) for the sort plus O(n) for the lookups; for small or rarely-printed maps this is invisible. Pre-allocate the slice with make([]string, 0, len(m)) to avoid append-reallocations. For repeated sorted access, consider keeping a parallel sorted-keys slice in sync with the map, or use a third-party ordered-map package.
