Есть ли какой-нибудь более простой / приятный способ получить часть ключей с карты в 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методом MapKeysstruct 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)), избавится от распределений, но я ожидаю, что все равно будет медленнее.
Я сделал схематичный тест по трем методам, описанным в других ответах.
Очевидно, что предварительное выделение фрагмента перед нажатием клавиш происходит быстрее, чем appending, но, что удивительно, 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)
}