Golang - получение части ключей с карты
Есть ли какой-нибудь более простой / приятный способ получить часть ключей с карты в Go?
В настоящее время я перебираю карту и копирую ключи в срез:
i := 0
keys := make([]int, len(mymap))
for k := range mymap {
keys[i] = k
i++
}
10 ответов
Например,
package main
func main() {
mymap := make(map[int]string)
keys := make([]int, 0, len(mymap))
for k := range mymap {
keys = append(keys, k)
}
}
Чтобы быть эффективным в Go, важно минимизировать распределение памяти.
Это старый вопрос, но вот мои два цента. Ответ PeterSO немного более краткий, но немного менее эффективный. Вы уже знаете, насколько большим он будет, поэтому вам даже не нужно использовать append:
keys := make([]int, len(mymap))
i := 0
for k := range mymap {
keys[i] = k
i++
}
В большинстве ситуаций это, вероятно, не будет иметь большого значения, но это не намного больше работы, и в моих тестах (используя карту с 1 000 000 случайных int64
ключей, а затем с помощью каждого метода генерировали массив ключей по десять раз), было приблизительно на 20% быстрее назначать элементы массива напрямую, чем использовать append.
Несмотря на то, что установка емкости исключает перераспределение, добавлению все равно приходится выполнять дополнительную работу, чтобы проверить, достигли ли вы емкости для каждого добавления.
Вы также можете взять массив ключей с типом []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]
}
В конце концов, очень скоро у Go появятся дженерики. Если это предложение (https://github.com/golang/go/issues/47649) превратится в первую версию реализации дженериков, мы сможем получить ключи любой карты с помощью
maps.Keys
:
// Keys returns the keys of the map m.
// The keys will be an indeterminate order.
func Keys[M constraints.Map[K, V], K comparable, V any](m M) []K
Пример использования очень прост
intMap := map[int]int{}
intKeys := maps.Keys(m1)
// intKeys is []int
strMap := map[string]int{}
strKeys := maps.Keys(m2)
// strKeys is []string
Я сделал схематичный тест по трем методам, описанным в других ответах.
Очевидно, что предварительное выделение фрагмента перед нажатием клавиш происходит быстрее, чем 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(запуск его на детской площадке прерывается, утверждая, что это занимает слишком много времени, поэтому, хорошо, запустите его локально.)
Лучший способ сделать это - использовать append
:
keys = []int{}
for k := range mymap {
keys = append(keys, k)
}
Кроме того, вам не повезло - иди не очень выразительный язык.
Предполагая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]
Посетите 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)
}
Общая версия (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 в стиле Lodash, основанная на Go 1.18+ Generics (карта, фильтр, содержит, найти...)
С этой библиотекой вы можете выполнять множество удобных операций, таких как сопоставление, фильтрация, уменьшение и многое другое. Также есть несколько помощников для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}