Есть ли какой-нибудь более простой / приятный способ получить часть ключей с карты в Go?
В настоящее время я перебираю карту и копирую ключи в срез:
i := 0
keys := make([]int, len(mymap))
for k := range mymap {
keys[i] = k
i++
}
Есть ли какой-нибудь более простой / приятный способ получить часть ключей с карты в Go?
В настоящее время я перебираю карту и копирую ключи в срез:
i := 0
keys := make([]int, len(mymap))
for k := range mymap {
keys[i] = k
i++
}
Ответы:
Например,
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 случайных int64
ключей и затем генерируя массив ключей десять раз с каждым методом), это было примерно На 20% быстрее назначать члены массива напрямую, чем использовать append.
Несмотря на то, что установка емкости исключает перераспределение, добавлению все равно приходится выполнять дополнительную работу, чтобы проверить, достигли ли вы емкости для каждого добавления.
for i, k := range mymap{
. Таким образом, вам не нужен i ++?
i, k := range mymap
, то i
будут ключи и k
будут значения, соответствующие этим ключам на карте. Это на самом деле не поможет вам заполнить кусок ключей.
Вы также можете взять массив ключей с типом []Value
методом MapKeys
struct Value
из пакета «refle»:
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
?
Лучший способ сделать это - использовать append
:
keys = []int{}
for k := range mymap {
keys = append(keys, k)
}
Кроме того, вам не повезло - иди не очень выразительный язык.
keys = make([]int, 0, len(mymap))
, избавится от распределений, но я ожидаю, что все равно будет медленнее.
Я сделал схематичный тест по трем методам, описанным в других ответах.
Очевидно, что предварительное выделение фрагмента перед нажатием клавиш происходит быстрее, чем append
ing, но, что удивительно, 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)
}