简体   繁体   English

如何在Go中获取地图键的排序列表?

[英]How to get sorted list of map keys in Go?

Let's imagine I have a map: map[string]string . 让我们想象一下我有一张地图: 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 . 然后我将有另一个类型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. 但问题是函数SortedMapKeys接受map[string]string参数。 So I need to write exactly the same function, with the only one difference - it will accept a map[string]bool . 所以我需要编写完全相同的函数,只有一个区别 - 它将接受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). 此外,我将不得不为所有这些函数编写相同的单元测试,这些函数实际上做同样的事情,因为它们的主体是100%相等(代码重复)。

Is there any way to create a generic function which could accept an map[string] of whatever ? 有没有办法创建一个可以接受任何map[string] 通用函数?

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. 由于map[string]boolmap[string]stringmap[string]Whatevermap[string]Whatever都是不同的类型,创建单个函数来对所有可能的map[string]*类型的键进行排序的唯一方法是通过反射。

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
}

Here's my 0.02$. 这是我的0.02美元。 Since keys extracting logic is unlikely to change and you want to keep everything in one place you can create variant and choose non-nil map from it: 由于密钥提取逻辑不太可能改变,并且您希望将所有内容保存在一个位置,因此您可以创建变量并从中选择非零映射:

type MapVariant struct {
    Bool   map[string]bool
    String map[string]string
}

func SortedMapKeys(variant MapVariant) (keyList []string) {
    if variant.String != nil {
        for k := range variant.String {
            keyList = append(keyList, k)
        }
        goto SORT
    }
    if variant.Bool != nil {
        for k := range variant.Bool {
            keyList = append(keyList, k)
        }
        goto SORT
    }

SORT:
    sort.Strings(keyList)
    return
}

Of course you can avoid goto statements by adding more conditions but I personally find it clearer. 当然,您可以通过添加更多条件来避免goto语句,但我个人觉得它更清楚。

Then you can use the function like: 然后你可以使用像这样的功能:

SortedMapKeys(MapVariant{
    Bool: map[string]bool{"a": true, "b": false}
})
SortedMapKeys(MapVariant{
    String: map[string]string{"c": "v1", "b": "v2"}
})

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM