package main
import (
"fmt"
"sort"
)
func main() {
m := map[string]int{"hello": 10, "foo": 20, "bar": 20}
n := map[int][]string{}
var a []int
for k, v := range m {
n[v] = append(n[v], k)
}
for k := range n {
a = append(a, k)
}
sort.Sort(sort.Reverse(sort.IntSlice(a)))
for _, k := range a {
for _, s := range n[k] {
fmt.Printf("%s, %d\n", s, k)
}
}
}
There's a new sort.Slice function in go 1.8, so now this is simpler.
package main
import (
"fmt"
"sort"
)
func main() {
m := map[string]int{
"something": 10,
"yo": 20,
"blah": 20,
}
type kv struct {
Key string
Value int
}
var ss []kv
for k, v := range m {
ss = append(ss, kv{k, v})
}
sort.Slice(ss, func(i, j int) bool {
return ss[i].Value > ss[j].Value
})
for _, kv := range ss {
fmt.Printf("%s, %d\n", kv.Key, kv.Value)
}
}
I often need to sort a map[string]int of something I’m counting and have been using the following.
func rankMapStringInt(values map[string]int) []string {
type kv struct {
Key string
Value int
}
var ss []kv
for k, v := range values {
ss = append(ss, kv{k, v})
}
sort.Slice(ss, func(i, j int) bool {
return ss[i].Value > ss[j].Value
})
ranked := make([]string, len(values))
for i, kv := range ss {
ranked[i] = kv.Key
}
return ranked
}
Use it to iterate over the keys in order of value
values := map[string]int{"foo": 10, "bar": 20, "baz": 1}
for i, index := range rankMapStringInt(values) {
fmt.Printf("%3d: %s -> %d", i, index, values[index])
}
In my case, I was dealing with a program that I created. In this program, I created a Map just like you, with string and int. Then I discovered like you that Go doesn't really have a built-in way to sort something like this. I read the other answers and didn't really like what I read.
So I tried to think about the problem differently. Go can use sort.Ints with a slice. Also, Go can use sort.Slice with a custom comparator. So instead of creating a Map of string and int, I created a struct of string and int. Then you can sort:
package main
import (
"fmt"
"sort"
)
type file struct {
name string
size int
}
func main() {
a := []file{
{"april.txt", 9}, {"may.txt", 7},
}
sort.Slice(a, func (d, e int) bool {
return a[d].size < a[e].size
})
fmt.Println(a)
}
This will not work for everyone, because maybe you will be forced to deal with a map someone else created. But it was useful for me. Good part is, unlike all the other answers, this one uses no loops.