🧱
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