มีวิธีที่ง่ายกว่าหรือดีกว่าในการรับชิ้นส่วนของคีย์จากแผนที่ใน 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 นั้นกระชับกว่าเล็กน้อย แต่ก็มีประสิทธิภาพน้อยกว่าเล็กน้อย คุณรู้แล้วว่ามันจะมีขนาดใหญ่เท่าไรคุณจึงไม่จำเป็นต้องใช้ผนวก:
keys := make([]int, len(mymap))
i := 0
for k := range mymap {
keys[i] = k
i++
}
ในสถานการณ์ส่วนใหญ่มันอาจจะไม่สร้างความแตกต่างมากนัก แต่มันก็ไม่ได้ผลมากนักและในการทดสอบของฉัน (ใช้แผนที่ที่มี 1,000,000 สุ่ม int64
ปุ่มและจากนั้นสร้างอาร์เรย์ของปุ่มสิบครั้งในแต่ละวิธี) เร็วขึ้น 20% ในการกำหนดสมาชิกของอาร์เรย์โดยตรงกว่าที่จะใช้ผนวก
แม้ว่าการตั้งค่าความจุจะลดการจัดสรรใหม่ แต่ยังคงต้องทำงานพิเศษเพิ่มเติมเพื่อตรวจสอบว่าคุณมีความจุครบตามแต่ละส่วนหรือไม่
for i, k := range mymap{
. ด้วยวิธีนี้คุณไม่จำเป็นต้องใช้ i ++?
i, k := range mymap
แล้วi
จะเป็นกุญแจและk
จะเป็นค่าที่สอดคล้องกับกุญแจเหล่านั้นในแผนที่ ที่จริงแล้วจะไม่ช่วยให้คุณเติมชิ้นส่วนของคีย์
นอกจากนี้คุณยังสามารถใช้อาร์เรย์ของคีย์พร้อมชนิด[]Value
ตามวิธีMapKeys
โครงสร้างValue
จากแพคเกจ "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
หรือไม่?
วิธีที่ดีกว่าในการทำเช่นนี้คือการใช้append
:
keys = []int{}
for k := range mymap {
keys = append(keys, k)
}
นอกจากนั้นคุณไม่มีโชค - โกไม่ใช่ภาษาที่แสดงออกมาก
keys = make([]int, 0, len(mymap))
จะกำจัดการจัดสรร แต่ฉันคาดว่ามันจะช้าลง
ฉันสร้างเกณฑ์มาตรฐานในสามวิธีที่อธิบายไว้ในคำตอบอื่น
เห็นได้ชัดว่าการจัดสรรชิ้นล่วงหน้าก่อนที่จะดึงกุญแจนั้นเร็วกว่า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 (เรียกใช้ในสนามเด็กเล่นยกเลิกการอ้างว่าใช้เวลานานเกินไปดังนั้นให้เรียกใช้ในเครื่อง)
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)
}