Go'daki bir haritadan bir dilim anahtar almanın daha basit / daha güzel bir yolu var mı?
Şu anda harita üzerinde yineleme ve bir dilim anahtarları kopyalama:
i := 0
keys := make([]int, len(mymap))
for k := range mymap {
keys[i] = k
i++
}
Go'daki bir haritadan bir dilim anahtar almanın daha basit / daha güzel bir yolu var mı?
Şu anda harita üzerinde yineleme ve bir dilim anahtarları kopyalama:
i := 0
keys := make([]int, len(mymap))
for k := range mymap {
keys[i] = k
i++
}
Yanıtlar:
Örneğin,
package main
func main() {
mymap := make(map[int]string)
keys := make([]int, 0, len(mymap))
for k := range mymap {
keys = append(keys, k)
}
}
Go'da verimli olmak için bellek ayırmalarını en aza indirmek önemlidir.
mymap
Yerel bir değişken değilse (ve bu nedenle büyümeye / daralmaya maruz kalıyorsa ), bunun tek uygun çözüm olduğunu unutmayın - mymap
başlatma keys
ve for
döngü arasındaki değişikliklerin boyutunun herhangi bir çıkış olmayacağını garanti eder. sınırları aşan sorunlar.
Bu eski bir soru, ama işte benim iki sentim. PeterSO'nun cevabı biraz daha özlü, ancak biraz daha az verimli. Ne kadar büyük olacağını zaten biliyorsunuz, bu yüzden append kullanmanıza bile gerek yok:
keys := make([]int, len(mymap))
i := 0
for k := range mymap {
keys[i] = k
i++
}
Çoğu durumda, muhtemelen çok fazla bir fark yaratmaz, ancak daha fazla iş değildir ve testlerimde (1.000.000 rastgele bir harita kullanarak) int64
anahtar ve daha sonra her yöntemle on kez anahtar dizisi oluşturmak), Dizinin üyelerini atamaktan doğrudan atamaktan% 20 daha hızlı.
Kapasitenin ayarlanması yeniden tahsisleri ortadan kaldırsa da, append'in her bir append'in kapasitesine ulaşıp ulaşmadığınızı kontrol etmek için ekstra iş yapması gerekir.
for i, k := range mymap{
? Bu şekilde i ++ 'a ihtiyacınız yok mu?
i, k := range mymap
, o i
zaman anahtar k
olacak ve haritadaki bu anahtarlara karşılık gelen değerler olacaktır. Bu aslında bir dilim anahtarı doldurmanıza yardımcı olmaz.
Ayrıca "reflektör" paketindeki yapı []Value
yöntemine MapKeys
göre türe sahip bir anahtar dizisi de alabilirsiniz 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]
}
[]string
?
Bunu yapmanın daha güzel bir yolu append
:
keys = []int{}
for k := range mymap {
keys = append(keys, k)
}
Bunun dışında şansınız kalmadı - Go çok etkileyici bir dil değil.
keys = make([]int, 0, len(mymap))
tahsislerden kurtulacak ama yine de daha yavaş olacağını umuyorum.
Diğer yanıtlarda açıklanan üç yöntem üzerinde kabataslak bir karşılaştırma yaptım.
Açıkça, tuşları çekmeden önce dilimi önceden ayırmak ing'den daha hızlıdır append
, ancak şaşırtıcı bir şekilde reflect.ValueOf(m).MapKeys()
yöntem, ikincisinden önemli ölçüde daha yavaştır:
❯ 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
İşte kod: https://play.golang.org/p/Z8O6a2jyfTH (oyun alanında çalıştırmak çok uzun sürdüğünü iddia ederek iptal ediyor, bu yüzden, yerel olarak çalıştırın.)
keysAppend
işlev sen kapasitesini ayarlayabilirsiniz keys
ile dizide make([]uint64, 0, len(m))
büyük ölçüde benim için fonksiyonun performansını değiştirdi.
Https://play.golang.org/p/dx6PTtuBXQW adresini ziyaret edin
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)
}