【Go】マップのキー・バリューを昇順・降順にソートする

# はじめに

Goのmapは順序を保持しないため、並び替えたい場合はひと工夫が必要です。

以下のようなマップをキー・バリューそれぞれで昇順・降順に並べ替えていきます。

```go
m := map[string]int{
    "Taro":  23,
    "Keiko": 41,
    "Jun":   11,
    "Azusa": 16,
}

// マップは順序を保持しない
for k, v := range m {
    fmt.Printf("Name: %s, Age: %d\n", k, v)
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/911578/1bd39d49-ef5d-5a21-039c-393540a67c2c.png)

## キー（文字列）でソートする

### 昇順

```go
// 先にキーだけソート
keys := []string{}
for k := range m {
    keys = append(keys, k)
}

// ソート（昇順）
sort.Strings(keys)

// もう一度for-rangeを使い、順に値を取り出す
for _, k := range keys {
    fmt.Printf("Name: %s, Age: %d\n", k, m[k])
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/911578/ca5fea33-0f8d-807a-1f2c-bb6cb8d90e1c.png)

### 降順

```go
// 先にキーだけソート
keys := []string{}
for k := range m {
    keys = append(keys, k)
}

// ソート（降順）
sort.Sort(sort.Reverse(sort.StringSlice(keys)))

// もう一度for-rangeを使い、順に値を取り出す
for _, k := range keys {
    fmt.Printf("Name: %s, Age: %d\n", k, m[k])
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/911578/dbc53199-1786-b276-a296-92e5a9fd5095.png)


## バリュー（Int）でソートする

### 昇順

```go
// 先にバリューだけソート
values := []int{}
for _, v := range m {
    values = append(values, v)
}

// ソート（昇順）
sort.Ints(values)

// valuesが小さい順になっているので、マップのバリューと比較し順に値を取り出す
for _, v := range values {
    for mk, mv := range m {
        if v == mv {
            fmt.Printf("Name: %s, Age: %d\n", mk, mv)
        }
    }
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/911578/5c358816-7ea2-d890-7f46-f0118d37b8dd.png)

###  降順

```go
// 先にバリューだけソート
values := []int{}
for _, v := range m {
    values = append(values, v)
}

// ソート（降順）
sort.Sort(sort.Reverse(sort.IntSlice(values)))

// valuesが小さい順になっているので、マップのバリューと比較し順に値を取り出す
for _, v := range values {
    for mk, mv := range m {
        if v == mv {
            fmt.Printf("Name: %s, Age: %d\n", mk, mv)
        }
    }
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/911578/56143cc8-b3f8-604a-2f2e-cae79dfc1637.png)

## サンプルコード

<details><summary>サンプルコード全体</summary>

```go
package main

import (
	"fmt"
	"sort"
)

func main() {
	m := map[string]int{
		"Taro":  23,
		"Keiko": 41,
		"Jun":   11,
		"Azusa": 16,
	}

	// mapは順序を保持しない
	fmt.Println("初期状態 -------------------------------------")
	for k, v := range m {
		fmt.Printf("Name: %s, Age: %d\n", k, v)
	}

	fmt.Println("キーでソート -------------------------------------")
	// 先にキーだけソート
	keys := []string{}
	for k := range m {
		keys = append(keys, k)
	}

	// ソート
	// 昇順
	sort.Strings(keys)
	// 降順
	// sort.Sort(sort.Reverse(sort.StringSlice(keys)))
	// もう一度for-rangeでソートされた順に値を取り出す
	for _, k := range keys {
		fmt.Printf("Name: %s, Age: %d\n", k, m[k])
	}

	// バリューでソートしたい場合 -------------------------------------
	fmt.Println("バリューでソート -------------------------------------")
	// 先にバリューだけソート
	values := []int{}
	for _, v := range m {
		values = append(values, v)
	}

	// ソート
	// 昇順
	sort.Ints(values)
	// 降順
	// sort.Sort(sort.Reverse(sort.IntSlice(values)))

	// valuesが小さい順になっているので、マップのバリューと比較し順に値を取り出す
	for _, v := range values {
		for mk, mv := range m {
			if v == mv {
				fmt.Printf("Name: %s, Age: %d\n", mk, mv)
			}
		}
	}
}

```
</details>

## 終わりに

やはりひと手間かかって少し面倒ですね......もっと良い方法があったらぜひ教えてください。

## 参考

https://pkg.go.dev/sort