如何在 Go 中获取映射键的排序列表?

问题描述 投票:0回答:4

假设我有一张地图:

map[string]string
。我想获取此地图的排序键列表。所以我可以做这样的事情:

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

然后我将拥有另一张

map[string]bool
类型的地图。我也想拿到它的钥匙。但问题是函数 SortedMapKeys 接受
map[string]string
参数。所以我需要编写完全相同的函数,只有一个区别 - 它会接受
map[string]bool

出于显而易见的原因,这不是一个选择。如果有一天我想改变获取和排序密钥的逻辑,我将需要跟踪和更新所有这些功能。另外,我必须为所有这些函数编写相同的单元测试,这些函数实际上做同样的事情,因为它们的主体 100% 相等(代码重复)。

有什么方法可以创建一个可以接受

map[string]
任何的通用函数吗?

list sorting dictionary go
4个回答
6
投票

由于

map[string]bool
map[string]string
map[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
}

对于中间解决方案,由于您可能只关心几种类型的组合,因此您可以使用类型开关来提取密钥

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
}

1
投票

这是我的 0.02 美元。由于密钥提取逻辑不太可能改变,并且您希望将所有内容保留在一个位置,因此您可以创建变体并从中选择非零映射:

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
}

当然你可以通过添加更多条件来避免 goto 语句,但我个人认为这样更清晰。

然后你可以使用如下功能:

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

1
投票

只是添加以防万一有人使用新版本的 Go >=1.18。对于这样的情况,我们可以使用泛型

func main() {
    s := map[string]string{
        "s1": "t",
        "s2": "t1",
    }

    b := map[string]bool{
        "b1": true,
        "b2": true,
    }
    k := SortedKeys(s)
    fmt.Printf("map keys %v", k)

    k = SortedKeys(b)
    fmt.Printf(" map keys %v", k)
}

func SortedKeys[V string | bool](m map[string]V) []string {
    keys := maps.Keys(m)
    sort.Strings(keys)
    return keys
}

前往游乐场的链接https://go.dev/play/p/2nHT8lt--Fj


0
投票

最新版本的 Go 支持:

theSortedSliceOfKeys := slices.Sorted(maps.Keys(theMap))
© www.soinside.com 2019 - 2024. All rights reserved.