Existe-t-il un moyen plus simple / plus agréable d'obtenir une tranche de clés d'une carte dans Go?
Actuellement, je suis en train d'itérer sur la carte et de copier les clés dans une tranche:
i := 0
keys := make([]int, len(mymap))
for k := range mymap {
keys[i] = k
i++
}
Réponses:
Par exemple,
package main func main() { mymap := make(map[int]string) keys := make([]int, 0, len(mymap)) for k := range mymap { keys = append(keys, k) } }
Pour être efficace dans Go, il est important de minimiser les allocations de mémoire.
la source
mymap
n'est pas une variable locale (et est donc sujette à croître / rétrécir), c'est la seule solution appropriée - cela garantit que si la taille desmymap
changements entre l'initialisation dekeys
et lafor
boucle, il n'y aura pas de sortie problèmes de délimitation.C'est une vieille question, mais voici mes deux cents. La réponse de PeterSO est légèrement plus concise, mais légèrement moins efficace. Vous savez déjà quelle sera sa taille, vous n'avez même pas besoin d'utiliser append:
keys := make([]int, len(mymap)) i := 0 for k := range mymap { keys[i] = k i++ }
Dans la plupart des situations, cela ne fera probablement pas beaucoup de différence, mais ce n'est pas beaucoup plus de travail, et dans mes tests (en utilisant une carte avec 1000000 de
int64
clés aléatoires , puis en générant le tableau de clés dix fois avec chaque méthode), il s'agissait de 20% plus rapide pour affecter les membres du tableau directement que pour utiliser append.Bien que la définition de la capacité élimine les réallocations, append doit encore effectuer un travail supplémentaire pour vérifier si vous avez atteint la capacité à chaque ajout.
la source
for i, k := range mymap{
. De cette façon, vous n'avez pas besoin du i ++?i, k := range mymap
, cei
seront des clés et desk
valeurs correspondant à ces clés dans la carte. Cela ne vous aidera pas réellement à remplir une tranche de clés.Vous pouvez également prendre un tableau de clés avec type
[]Value
par méthodeMapKeys
de struct àValue
partir du package "refléter":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] }
la source
[]string
?Une meilleure façon de le faire serait d'utiliser
append
:keys = []int{} for k := range mymap { keys = append(keys, k) }
À part cela, vous n'avez pas de chance - Go n'est pas un langage très expressif.
la source
keys = make([]int, 0, len(mymap))
va supprimer les allocations, mais je pense que ce sera encore plus lent.J'ai fait un point de référence sommaire sur les trois méthodes décrites dans d'autres réponses.
Évidemment, pré-allouer la tranche avant de tirer les touches est plus rapide que
append
ing, mais étonnamment, lareflect.ValueOf(m).MapKeys()
méthode est nettement plus lente que cette dernière:❯ 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
Voici le code: https://play.golang.org/p/Z8O6a2jyfTH (l'exécuter dans le terrain de jeu s'interrompt en affirmant que cela prend trop de temps, alors, eh bien, exécutez-le localement.)
la source
keysAppend
fonction, vous pouvez définir la capacité de lakeys
baie avecmake([]uint64, 0, len(m))
, ce qui a radicalement changé les performances de cette fonction pour moi.Visitez 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) }
la source