2

How can I loop through a map on a constant order multiple times ?

In my go code I am looping through a map twice but the values are not appearing on the same order on both loops :

fieldMap := map[string]int{...}

First loop :

for k, _ := range fieldMap {...}

Second loop :

for _, v := range fieldMap {...}

AlexB
  • 3,518
  • 4
  • 29
  • 46
  • 2
    This cannot be done with a map alone http://stackoverflow.com/a/11853555/1072106. – JoshStrange Jun 20 '15 at 18:18
  • Looping over a map gives an intentionally randomized iteration order. If yo want a consistent iteration order, you have to extract the keys and sort them. – Vatine Jun 21 '15 at 11:55

2 Answers2

4

Save the keys in the first loop and use them in the second loop:

keys := make([]string, 0, len(m))
for k, v := range m {
    fmt.Println(k, v)
    keys = append(keys, k)
}
for _, k := range keys {
    fmt.Println(k, m[k])
}

Playground: http://play.golang.org/p/MstH20wkNN.

Ainar-G
  • 34,563
  • 13
  • 93
  • 119
  • It definitaly works but is there any way to do it without creating an array in addition to the map ? – AlexB Jun 20 '15 at 18:18
  • 5
    Firstly, `keys` is a slice, not an array. Secondly, no. The order of map iteration is not guaranteed. If you want to reliably iterate over a map in a certain order, you need to create that order yourself. – Ainar-G Jun 20 '15 at 18:26
  • 1
    I agree with your general point that you need to create that order themselves. I just wanted to add that while `keys` is a slice, it will be backed by an array. I assume the reason for the question was that they didn't want to allocate any more memory, and slices aren't free. – Danver Braganza Jun 23 '15 at 18:06
4

Go makes sure that you cannot rely on a map's order as stated in this blog post https://blog.golang.org/go-maps-in-action#TOC_7.

When iterating over a map with a range loop, the iteration order is not specified and is not guaranteed to be the same from one iteration to the next. Since Go 1 the runtime randomizes map iteration order, as programmers relied on the stable iteration order of the previous implementation. If you require a stable iteration order you must maintain a separate data structure that specifies that order.

Ainar-G's answer is correct, but here is a variation of it while incorporating this answer... https://stackoverflow.com/a/27848197/3536948

keys := make([]string, len(m))
i := 0
for k, _ := range m {
    keys[i] = k
    i += 1
}
for _, k := range keys {
    fmt.Println(m[k])
}

Playground: http://play.golang.org/p/64onPZNODm

Community
  • 1
  • 1
poopoothegorilla
  • 764
  • 7
  • 13