[英]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)
}
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
类型的助手
Creates an array of the map keys.创建映射键的数组。
keys := lo.Keys[string, int](map[string]int{"foo": 1, "bar": 2})
// []string{"bar", "foo"}
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.