🧱
Go 1.23でmapのキーをソートする
結論
Go 1.23.0からは、for
文一つでmap
を順序付きでループできる。
var m map[int]string
for _, k := range slices.Sorted(maps.Keys(m)) {
fmt.Println("Key:", k, "Value:", m[k])
}
これまでのやり方
Goのmap
をrange
ループでイテレーションする際、キーの順番は保証されておらず、実行するたびに変わります。
var m map[int]string
// 実行するたびに順番が変わる。
for k, v := range m {
fmt.Println("Key:", k, "Value:", v)
}
順番を保証するには、事前にキーの配列を作成し、それをソートして使います。
例えば、キーの配列をslices.Sort
関数でソートし、その配列をrange
ループで回します。
var m map[int]string
var keys []int
// ソート済みのキー配列を用意する。
for k := range m {
keys = append(keys, k)
}
slices.Sort(keys)
// 必ずキーの昇順で表示される。
for _, k := range keys {
fmt.Println("Key:", k, "Value:", m[k])
}
Go 1.23でのやり方
map
をイテレーションするのにfor
文が二つ必要なのは少々気が利いていません。
Go 1.23.0からは、標準ライブラリを使ってよりコンパクトに書けるようになります。
肝となるのは、次の2つの関数です:
-
maps
パッケージに追加されたfunc Keys[Map ~map[K]V, K comparable, V any](m Map) iter.Seq[K]
- 戻り値はキーをランダムな順番で返すイテレーター。
-
slices
パッケージに追加されたfunc Sorted[E cmp.Ordered](seq iter.Seq[E]) []E
- 引数は
cmp.Ordered
を満たす要素のイテレーター。 - 戻り値はソート済みの配列。
- 引数は
maps.Keys
とslices.Sorted
を使うと、キーの昇順で要素を出力するプログラムは次のように書けます。
var m map[int]string
// キーの昇順で出力される。
for _, k := range slices.Sorted(maps.Keys(m)) {
fmt.Println("Key:", k, "Value:", m[k])
}
キーの降順で要素を出力したい場合は、slices.SortedFunc
が使えます。
var m map[int]string
// キーの降順で出力される。
for _, k := range slices.SortedFunc(maps.Keys(m), func (a, b int) int {
return cmp.Compare(b, a)
}) {
fmt.Println("Key:", k, "Value:", m[k])
}
Discussion