listsortingdictionarygo

How to get sorted list of map keys in Go?


Let's imagine I have a map: map[string]string. I would like to get the list of sorted keys for this map. So I could do something like this:

func SortedMapKeys(m map[string]string) (keyList []string) {
    for key := range m {
        keyList = append(keyList, key)
    }
    sort.Strings(keyList)
    return
}

Then I will have another map of type map[string]bool. I would like to get it's keys also. But the problem is that function SortedMapKeys accepts a map[string]string argument. So I need to write exactly the same function, with the only one difference - it will accept a map[string]bool.

For obvious reasons it's not an option. If one day I would like to change the logic of how I get and sort my keys, I will need to track and update all these functions. Also, I will have to write the same unit tests for all these functions which actually do the same thing since their bodies are 100% equal (code duplicate).

Is there any way to create a generic function which could accept an map[string] of whatever?


Solution

  • Since map[string]bool and map[string]string and map[string]Whatever are all distinct types, the only way to create a single function to sort the keys of all possible map[string]* types is via reflection.

    func SortedMapKeys(m interface{}) (keyList []string) {
        keys := reflect.ValueOf(m).MapKeys()
    
        for _, key := range keys {
            keyList = append(keyList, key.Interface().(string))
        }
        sort.Strings(keyList)
        return
    }
    

    For an in-between solution, since there are probably only a few combinations of types you're concerned with, you can use a type switch to extract the keys

    func SortedMapKeys(m interface{}) (keyList []string) {
        switch m := m.(type) {
        case map[string]string:
            for k := range m {
                keyList = append(keyList, k)
            }
        case map[string]bool:
            for k := range m {
                keyList = append(keyList, k)
            }
        default:
            panic("unknown map type")
        }
    
        sort.Strings(keyList)
        return
    }