How to fix Go map randomness
Apr 18, 2020 06:29 · 351 words · 2 minute read
The problem
In Go, when you use map
to store stuff and then want to iterate over the keys or value, the order of iteration
is not deterministic.
The following sample code will print
m := make(map[int]int)
for i := 0; i < 8; i++ {
m[i] = i
}
for k, v := range m {
fmt.Println(k, v)
}
this output for one run
6 6
7 7
0 0
1 1
2 2
3 3
4 4
5 5
but for another, this total different result
7 7
0 0
1 1
2 2
3 3
4 4
5 5
6 6
Not very handy when you are designing a deterministic and reproducible environment. Fortunately, you can use an ordered map.
The solution: Ordered map
The orderedmap module from elliotchance provides an implementation of an Ordered map. It keeps instead of the native map the order of insertion
m := orderedmap.NewOrderedMap()
for i := 0; i < 10; i++ {
m.Set(i, i)
}
for _, key := range m.Keys() {
value, _:= m.Get(key)
fmt.Println(key, value)
}
prints
0 0
1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
9 9
Problem solved!
But at what cost? Well if your map is not very large, the performance impact will not be big. A benchmark is available on its README.
Here a run on my laptop
goos: linux
goarch: amd64
pkg: github.com/elliotchance/orderedmap
BenchmarkAll/BenchmarkOrderedMap_Keys-12 212968 6351 ns/op 16385 B/op 1 allocs/op
BenchmarkAll/BenchmarkOrderedMap_Set-12 2048703 496 ns/op 208 B/op 3 allocs/op
BenchmarkAll/BenchmarkMap_Set-12 10569781 139 ns/op 42 B/op 0 allocs/op
BenchmarkAll/BenchmarkOrderedMap_Get-12 34637158 31.0 ns/op 0 B/op 0 allocs/op
BenchmarkAll/BenchmarkMap_Get-12 72673410 15.8 ns/op 0 B/op 0 allocs/op
BenchmarkAll/BenchmarkOrderedMap_Delete-12 2147473 586 ns/op 203 B/op 3 allocs/op
BenchmarkAll/BenchmarkMap_Delete-12 6536530 208 ns/op 36 B/op 0 allocs/op
BenchmarkAll/BenchmarkOrderedMap_Iterate-12 27877 46138 ns/op 16391 B/op 1 allocs/op
BenchmarkAll/BenchmarkMap_Iterate-12 87426 13682 ns/op 0 B/op 0 allocs/op
The iteration and set operations are 3x slower than the map
. However, in my case, the overall time taken by the map
very small compared to the rest of the application, so no problem using this ordered map.
Happy coding!