Wednesday, March 26, 2025

golang sorting maps by value and returning a slice of keys

Golang 1.23 Added new slices functions to help sort. These are useful for sorting maps by values or by keys.

In my previous post I went through some examples about how to sort by the keys of a map and return an array of values.

This does the converse and I provide examples to sort by the values of a map and return an array of keys.

https://www.geeksforgeeks.org/how-to-sort-golang-map-by-keys-or-values/ was helpful to see how to do it using the sort package. When I looked at the api docs, it suggested using the slices package:

"Note: in many situations, the newer slices.SortStableFunc function is more ergonomic and runs faster."

// Sort by value with map[int]string and map[string]int
func main() {
fmt.Println("Start")

fmt.Println("Sorting by Value in a map with int keys and string values")

intStringMap := map[int]string{
22: "z",
111: "y",
3333: "x",
}

// 1) Using sort package
intKeys := slices.Collect(maps.Keys(intStringMap))

sort.SliceStable(intKeys, func(i, j int) bool {
return intStringMap[intKeys[i]] < intStringMap[intKeys[j]]
})

fmt.Println("1) Using sort package:", intKeys) // [3333 111 22]

// 2) Using slices package
intKeySlice := slices.Collect(maps.Keys(intStringMap))

slices.SortStableFunc(intKeySlice, func(a, b int) int {
return cmp.Compare(intStringMap[a], intStringMap[b])
})

fmt.Println("2) Sort Keys in place", intKeySlice) // [3333 111 22]

fmt.Println()
fmt.Println("Sorting by Value in a map with string keys and int values")

stringIntMap := map[string]int{
"z": 222,
"y": 11,
"x": 3333,
}

// 1) Using sort package. API says consider using slices package
stringKeys := slices.Collect(maps.Keys(stringIntMap))

sort.SliceStable(stringKeys, func(i, j int) bool {
return stringIntMap[stringKeys[i]] < stringIntMap[stringKeys[j]]
})

fmt.Println("1) Using sort package:", stringKeys) // [y z x]

// 2) returns a slice where the values are the keys of stringIntMap
// sorts the keys in place

keySlice := slices.Collect(maps.Keys(stringIntMap))

slices.SortStableFunc(keySlice, func(a, b string) int {
return cmp.Compare(stringIntMap[a], stringIntMap[b])
})

fmt.Printf("2) Sort In Place: %v\n", keySlice) // [y z x]

// 3) returns a slice where the values are the keys of stringIntMap
keys := maps.Keys(stringIntMap) // an Iter

keysSortedByValue := slices.SortedStableFunc(keys, func(a, b string) int {
return cmp.Compare(stringIntMap[a], stringIntMap[b])
})

fmt.Printf("3) New Variable: %v\n", keysSortedByValue) // [y z x]

// Output the keys and values
fmt.Println("Print the stringIntMap in order")
for _, k := range keysSortedByValue {
fmt.Printf("%s: %d\n", k, stringIntMap[k])
}
// y: 11
// z: 222
// x: 3333

fmt.Println("Done")
}

 

Tuesday, March 25, 2025

Golang how to sort the keys in a map and create a new array

Golang maps are purposely unordered. If you add the values "b": 2 and "a": 1 to a map, iterating this will sometimes get "a" first, and other times "b" first.

With many languages, they have data types like arrays or ordered maps that allow you to traverse the array in the order of keys. Others have a built a method to output a new array in key order.

Golang requires the use of a few helper methods to convert a map into a key sorted slice.

package main

import (
"fmt"
"maps"
"slices"
)

func main() {
fmt.Println("Start")

intStringMap := map[int]string{
2: "b",
1: "a",
3: "c",
}

// Two ways to get the keys from a map and sort them
// intKeys := slices.Collect(maps.Keys(intStringMap))
// sort.Ints(intKeys)
intKeys := slices.Sorted(maps.Keys(intStringMap))

sortedIntStringArray := make([]string, 0)

for _, key := range intKeys {
sortedIntStringArray = append(sortedIntStringArray, intStringMap[key])
}

fmt.Printf("%v\n", sortedIntStringArray) // [a b c]

stringIntMap := map[string]int{
"b": 2,
"a": 1,
"c": 3,
}

// Same as above but with a string int map
// stringKeys := slices.Collect(maps.Keys(stringIntMap))
// sort.Strings(stringKeys)
stringKeys := slices.Sorted(maps.Keys(stringIntMap))

sortedStringIntArray := make([]int, 0)

for _, key := range stringKeys {
sortedStringIntArray = append(sortedStringIntArray, stringIntMap[key])
}

fmt.Printf("%v\n", sortedStringIntArray) // [1 2 3]

fmt.Println("Done")
}