提问人:Saswat Padhi 提问时间:1/26/2014 最后编辑:blackgreenSaswat Padhi 更新时间:9/21/2023 访问量:451277
从地图中获取密钥切片
Getting a slice of keys from a map
问:
有没有更简单/更好的方法可以从 Go 中的地图中获取一部分键?
目前,我正在遍历地图并将键复制到切片:
i := 0
keys := make([]int, len(mymap))
for k := range mymap {
keys[i] = k
i++
}
答:
一个更好的方法是使用:append
keys = []int{}
for k := range mymap {
keys = append(keys, k)
}
除此之外,你就不走运了——Go 不是一种非常富有表现力的语言。
评论
keys = make([]int, 0, len(mymap))
例如
package main
func main() {
mymap := make(map[int]string)
keys := make([]int, 0, len(mymap))
for k := range mymap {
keys = append(keys, k)
}
}
为了在 Go 中提高效率,尽量减少内存分配非常重要。
评论
mymap
mymap
keys
for
这是一个老问题,但这是我的两分钱。PeterSO的回答稍微简洁一些,但效率略低一些。你已经知道它会有多大,所以你甚至不需要使用 append:
keys := make([]int, len(mymap))
i := 0
for k := range mymap {
keys[i] = k
i++
}
在大多数情况下,它可能不会有太大的区别,但它不会有更多的工作,在我的测试中(使用具有 1,000,000 个随机键的映射,然后用每种方法生成键数组十次),直接分配数组成员比使用 append 快约 20%。int64
尽管设置容量可以消除重新分配,但追加仍然需要执行额外的工作来检查每个追加是否已达到容量。
评论
for i, k := range mymap{
i, k := range mymap
i
k
您还可以从包“reflect”中获取一个类型为 by struct 方法的键数组:[]Value
MapKeys
Value
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]
}
评论
[]string
我对其他回复中描述的三种方法做了一个粗略的基准测试。
显然,在拉动密钥之前预先分配切片比 ing 快,但令人惊讶的是,该方法明显慢于后者: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
代码如下:https://play.golang.org/p/Z8O6a2jyfTH(在操场上运行它会中止,声称它需要太长时间,所以,好吧,在本地运行它。
评论
keysAppend
keys
make([]uint64, 0, len(m))
访问 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)
}
Go 现在有泛型。您可以使用地图获取任何地图的密钥。键
。
用法示例:
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
包位于 中。这是实验性的,超出了 Go 兼容性保证。他们的目标是在未来将其移动到 Go 1.19 的 std 库中。golang.org/x/exp/maps
游乐场: https://go.dev/play/p/fkm9PrJYTly
对于那些不喜欢导入 exp 包的人,这里是源代码(最初由 Ian Lance Taylor 编写),正如你所看到的,它非常简单:
// 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
}
注意:在 Go 1.21 中,软件包的一部分已移至标准库中,但未移至 .有关详细信息,请参阅 Go 问题图:删除 Go 1.21 tl 的键和值;dr 该方法最终可能会具有不同的签名。因此,在 Go 1.21 中,这里提供的解决方案(使用或复制源代码)仍然适用。maps
maps.Keys
Keys
x/exp/maps
的 answer 的通用版本 (go 1.18+)。Vinay Pai
// 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
}
有一个很酷的库叫做 lo
基于 Go 1.18+ 泛型的 Lodash 风格的 Go 库(map、filter、contains、find...
有了这个库,你可以做许多方便的操作,如地图、过滤、减少等等。还有一些类型的帮助程序map
钥匙
创建映射键的数组。
keys := lo.Keys[string, int](map[string]int{"foo": 1, "bar": 2})
// []string{"bar", "foo"}
值
创建映射值的数组。
values := lo.Values[string, int](map[string]int{"foo": 1, "bar": 2})
// []int{1, 2}
假设是 类型,您可以使用标准库中的实验性 maps 包获取键和值:map
map[int]string
package main
import (
"fmt"
"golang.org/x/exp/maps"
)
func main() {
mymap := map[int]string{1: "foo", 2: "bar", 3: "biz"}
fmt.Println(maps.Keys(mymap))
fmt.Println(maps.Values(mymap))
}
输出:
[2 3 1]
[bar biz foo]
评论
下一个:初始化空切片的正确方法
评论