简体   繁体   English

从地图中获取一部分键

[英]Getting a slice of keys from a map

Is there any simpler/nicer way of getting a slice of keys from a map in Go?有没有更简单/更好的方法从 Go 中的地图中获取一部分键?

Currently I am iterating over the map and copying the keys to a slice:目前我正在遍历地图并将键复制到切片中:

i := 0
keys := make([]int, len(mymap))
for k := range mymap {
    keys[i] = k
    i++
}

This is an old question, but here's my two cents. 这是一个老问题,但这是我的两分钱。 PeterSO's answer is slightly more concise, but slightly less efficient. PeterSO的答案稍微简洁一些,但效率稍差。 You already know how big it's going to be so you don't even need to use append: 你已经知道它有多大,所以你甚至不需要使用append:

keys := make([]int, len(mymap))

i := 0
for k := range mymap {
    keys[i] = k
    i++
}

In most situations it probably won't make much of a difference, but it's not much more work, and in my tests (using a map with 1,000,000 random int64 keys and then generating the array of keys ten times with each method), it was about 20% faster to assign members of the array directly than to use append. 在大多数情况下,它可能不会产生太大的影响,但它不是更多的工作,并且在我的测试中(使用带有1,000,000个随机int64键的映射,然后使用每种方法生成十次键的数组),它是直接分配数组成员比使用append快20%。

Although setting the capacity eliminates reallocations, append still has to do extra work to check if you've reached capacity on each append. 尽管设置容量会消除重新分配,但追加仍然需要做额外的工作来检查每个附加是否达到了容量。

For example, 例如,

package main

func main() {
    mymap := make(map[int]string)
    keys := make([]int, 0, len(mymap))
    for k := range mymap {
        keys = append(keys, k)
    }
}

To be efficient in Go, it's important to minimize memory allocations. 为了在Go中高效,最小化内存分配很重要。

You also can take an array of keys with type []Value by method MapKeys of struct Value from package "reflect": 您还可以使用类型为[]Value的键数组,方法MapKeys的struct Value from package“reflect”:

package main

import (
    "fmt"
    "reflect"
)

func main() {
    abc := map[string]int{
        "a": 1,
        "b": 2,
        "c": 3,
    }

    keys := reflect.ValueOf(abc).MapKeys()

    fmt.Println(keys) // [a b c]
}

Go now has generics. Go 现在有泛型。 We can get the keys of any map with maps.Keys .我们可以使用maps.Keys获取任何地图的键。

Example usage is very simple示例用法很简单

    intMap := map[int]int{1: 1, 2: 2}
    intKeys := maps.Keys(intMap)
    // intKeys is []int
    fmt.Println(intKeys)

    strMap := map[string]int{"alpha": 1, "bravo": 2}
    strKeys := maps.Keys(strMap)
    // strKeys is []string
    fmt.Println(strKeys)

maps package is found in golang.org/x/exp/maps . maps包位于golang.org/x/exp/maps This is experimental and outside of Go compatibility guarantee.这是实验性的,不属于 Go 兼容性保证。 They aim to move it into the std lib in Go 1.19他们的目标是将其移入 Go 1.19 中的 std lib

It works on go playground https://go.dev/play/p/fkm9PrJYTly它适用于去游乐场https://go.dev/play/p/fkm9PrJYTly

Maybe a few users don't like to import exp packages, we can copy the source code :可能有些用户不喜欢导入exp包,我们可以复制源码

// Keys returns the keys of the map m.
// The keys will be an indeterminate order.
func Keys[M ~map[K]V, K comparable, V any](m M) []K {
    r := make([]K, 0, len(m))
    for k := range m {
        r = append(r, k)
    }
    return r
}

A nicer way to do this would be to use append : 一个更好的方法是使用append

keys = []int{}
for k := range mymap {
    keys = append(keys, k)
}

Other than that, you're out of luck—Go isn't a very expressive language. 除此之外,你运气不好 - Go不是一个非常富有表现力的语言。

I made a sketchy benchmark on the three methods described in other responses. 我对其他回答中描述的三种方法做了粗略的基准测试。

Obviously pre-allocating the slice before pulling the keys is faster than append ing, but surprisingly, the reflect.ValueOf(m).MapKeys() method is significantly slower than the latter: 显然,在拉动键之前预先分配切片比append更快,但令人惊讶的是, reflect.ValueOf(m).MapKeys()方法明显慢于后者:

❯ go run scratch.go
populating
filling 100000000 slots
done in 56.630774791s
running prealloc
took: 9.989049786s
running append
took: 18.948676741s
running reflect
took: 25.50070649s

Here's the code: https://play.golang.org/p/Z8O6a2jyfTH (running it in the playground aborts claiming that it takes too long, so, well, run it locally.) 这是代码: https//play.golang.org/p/Z8O6a2jyfTH (在游乐场中运行它声称它需要太长时间,所以,好吧,在本地运行它。)

Visit https://play.golang.org/p/dx6PTtuBXQW 访问https://play.golang.org/p/dx6PTtuBXQW

package main

import (
    "fmt"
    "sort"
)

func main() {
    mapEg := map[string]string{"c":"a","a":"c","b":"b"}
    keys := make([]string, 0, len(mapEg))
    for k := range mapEg {
        keys = append(keys, k)
    }
    sort.Strings(keys)
    fmt.Println(keys)
}

A generic version (go 1.18+) of Vinay Pai 's answer . Vinay Pai答案的通用版本(1.18+)。

// MapKeysToSlice extract keys of map as slice,
func MapKeysToSlice[K comparable, V any](m map[K]V) []K {
    keys := make([]K, len(m))

    i := 0
    for k := range m {
        keys[i] = k
        i++
    }
    return keys
}

There is a cool lib called lo有一个很酷的库叫做lo

A Lodash-style Go library based on Go 1.18+ Generics (map, filter, contains, find...)基于 Go 1.18+ 泛型(映射、过滤器、包含、查找...)的 Lodash 风格的 Go 库

With this lib you could do many convinient operations like map, filter, reduce and more.有了这个库,你可以做很多方便的操作,比如 map、filter、reduce 等等。 Also there are some helpers for map type还有一些map类型的助手

Keys钥匙

Creates an array of the map keys.创建映射键的数组。

keys := lo.Keys[string, int](map[string]int{"foo": 1, "bar": 2})
// []string{"bar", "foo"}

Values价值观

Creates an array of the map values.创建地图值的数组。

values := lo.Values[string, int](map[string]int{"foo": 1, "bar": 2})
// []int{1, 2}

https://github.com/chenhg5/collection is a package which can help you. https://github.com/chenhg5/collection是一个可以帮助您的软件包。 like this: 像这样:

a := map[string]interface{}{
    "name": "mike",
    "sex":  1,
}

fmt.Println(Collect(a).Keys().ToStringArray())

// Output: []string{"name", "sex"}

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

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