【golang】mapの要素順は変動する


■環境
OS X El Capitan 10.11.6
go 1.8 darwin/amd64

タイトルの件、ちょっと引っかかったのでメモです。

golangで変数にmapを格納する場合、その要素の順番は
呼び出すたびに変わります。

以下サンプルコードです。
mapをrangeで取り出しながらforで回し、標準出力する
という処理を3回繰り返します。

package main  
  
import (  
	"fmt"  
)  
  
func main() {  
	// create new map  
	fruitColor := make(map[string]string)  
	fruitColor["pineapple"] = "yellow"  
	fruitColor["apple"] = "red"  
	fruitColor["grape"] = "purple"  
	fruitColor["melon"] = "green"  
  
	// printout 3 times  
	for i := 1; i <= 3; i++ {  
		fmt.Println(fmt.Sprintf("===== %d times =====", i))  
		for name, color := range fruitColor {  
			fmt.Println(fmt.Sprintf("%s is %s", name, color))  
		}  
	}  
}  

これを実行すると、このように出力されます。
要素順は変動するので、実行する度に変わると思います。

===== 1 times =====  
apple is red  
grape is purple  
melon is green  
pineapple is yellow  
===== 2 times =====  
grape is purple  
melon is green  
pineapple is yellow  
apple is red  
===== 3 times =====  
melon is green  
pineapple is yellow  
apple is red  
grape is purple

上記のような順不同なアプリケーションだとしても、
ユーザが画面を表示する度に順番が変わるのは気持ち悪いので
sliceを使って表示順を保持しておいた方が良いです。

sliceを使う例は以下の通りです。

package main  
  
import (  
	"fmt"  
)  
  
func main() {  
	// create new map  
	fruitColor := make(map[string]string)  
	fruitColor["pineapple"] = "yellow"  
	fruitColor["apple"] = "red"  
	fruitColor["grape"] = "purple"  
	fruitColor["melon"] = "green"  
	// set display order  
	fruitList := []string{"pineapple","apple","grape","melon"}  
  
	// printout 3 times  
	for i := 1; i <= 3; i++ {  
		fmt.Println(fmt.Sprintf("===== %d times =====", i))  
		for _, name := range fruitList {  
			fmt.Println(fmt.Sprintf("%s is %s", name, fruitColor[name]))  
		}  
	}  
}  

これを実行すると以下のようになります。

===== 1 times =====  
pineapple is yellow  
apple is red  
grape is purple  
melon is green  
===== 2 times =====  
pineapple is yellow  
apple is red  
grape is purple  
melon is green  
===== 3 times =====  
pineapple is yellow  
apple is red  
grape is purple  
melon is green