Czy jest jakiś prostszy / ładniejszy sposób na zdobycie kawałka klucza z mapy w Go?
Obecnie iteruję po mapie i kopiuję klucze do wycinka:
i := 0
keys := make([]int, len(mymap))
for k := range mymap {
keys[i] = k
i++
}
Czy jest jakiś prostszy / ładniejszy sposób na zdobycie kawałka klucza z mapy w Go?
Obecnie iteruję po mapie i kopiuję klucze do wycinka:
i := 0
keys := make([]int, len(mymap))
for k := range mymap {
keys[i] = k
i++
}
Odpowiedzi:
Na przykład,
package main
func main() {
mymap := make(map[int]string)
keys := make([]int, 0, len(mymap))
for k := range mymap {
keys = append(keys, k)
}
}
Aby być wydajnym w Go, ważne jest, aby zminimalizować przydziały pamięci.
mymap
nie jest zmienną lokalną (i dlatego podlega wzrostowi / zmniejszaniu), jest to jedyne właściwe rozwiązanie - zapewnia, że jeśli rozmiar mymap
zmian między inicjalizacją keys
i for
pętlą nie będzie żadnych problemy z ograniczeniami.
To stare pytanie, ale oto moje dwa centy. Odpowiedź PeterSO jest nieco bardziej zwięzła, ale nieco mniej wydajna. Wiesz już, jak duży będzie, więc nie musisz nawet używać append:
keys := make([]int, len(mymap))
i := 0
for k := range mymap {
keys[i] = k
i++
}
W większości sytuacji prawdopodobnie nie będzie to miało większego znaczenia, ale nie będzie to dużo więcej pracy, aw moich testach (przy użyciu mapy z 1 000 000 losowych int64
kluczy, a następnie wygenerowaniu tablicy kluczy dziesięć razy przy każdej metodzie) chodziło o 20% szybciej, aby przypisać członków tablicy bezpośrednio niż użyć append.
Chociaż ustawienie pojemności eliminuje realokacje, append wciąż musi wykonać dodatkową pracę, aby sprawdzić, czy osiągnięto pojemność na każdym append.
for i, k := range mymap{
. W ten sposób nie potrzebujesz i ++?
i, k := range mymap
, to i
będą klucze i k
będą wartości odpowiadające tym kluczom na mapie. To naprawdę nie pomoże ci zapełnić kawałka kluczy.
Możesz także pobrać tablicę kluczy typu za []Value
pomocą metody MapKeys
struct Value
z pakietu „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]
}
[]string
?
Lepszym sposobem na to byłoby użycie append
:
keys = []int{}
for k := range mymap {
keys = append(keys, k)
}
Poza tym nie masz szczęścia - Go nie jest bardzo ekspresyjnym językiem.
keys = make([]int, 0, len(mymap))
pozbędzie się alokacji, ale spodziewam się, że nadal będzie wolniejsze.
Zrobiłem szkicowy test porównawczy dla trzech metod opisanych w innych odpowiedziach.
Oczywiście wcześniejsze przydzielenie wycinka przed wyciągnięciem kluczy jest szybsze niż append
ing, ale, co zaskakujące, reflect.ValueOf(m).MapKeys()
metoda jest znacznie wolniejsza niż ta ostatnia:
❯ 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
Oto kod: https://play.golang.org/p/Z8O6a2jyfTH (uruchamianie go na boisku przerywa twierdzenie, że trwa to zbyt długo, więc cóż, uruchom go lokalnie.)
keysAppend
funkcji możesz ustawić pojemność keys
tablicy make([]uint64, 0, len(m))
, co drastycznie zmieniło dla mnie wydajność tej funkcji.
Odwiedź 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)
}