Có cách nào đơn giản / đẹp hơn để lấy một lát chìa khóa từ bản đồ trong Go không?
Hiện tại tôi đang lặp lại trên bản đồ và sao chép các phím vào một lát:
i := 0
keys := make([]int, len(mymap))
for k := range mymap {
keys[i] = k
i++
}
Có cách nào đơn giản / đẹp hơn để lấy một lát chìa khóa từ bản đồ trong Go không?
Hiện tại tôi đang lặp lại trên bản đồ và sao chép các phím vào một lát:
i := 0
keys := make([]int, len(mymap))
for k := range mymap {
keys[i] = k
i++
}
Câu trả lời:
Ví dụ,
package main
func main() {
mymap := make(map[int]string)
keys := make([]int, 0, len(mymap))
for k := range mymap {
keys = append(keys, k)
}
}
Để có hiệu quả trong Go, điều quan trọng là giảm thiểu phân bổ bộ nhớ.
mymap
không phải là biến cục bộ (và do đó có thể tăng / thu hẹp), thì đây là giải pháp phù hợp duy nhất - nó đảm bảo rằng nếu kích thước mymap
thay đổi giữa khởi tạo keys
và for
vòng lặp, sẽ không có bất kỳ biến đổi nào vấn đề giới hạn.
Đây là một câu hỏi cũ, nhưng đây là hai xu của tôi. Câu trả lời của PeterSO ngắn gọn hơn một chút, nhưng hơi kém hiệu quả. Bạn đã biết nó sẽ lớn đến mức nào nên bạn thậm chí không cần sử dụng phụ lục:
keys := make([]int, len(mymap))
i := 0
for k := range mymap {
keys[i] = k
i++
}
Trong hầu hết các tình huống, nó có thể sẽ không tạo ra nhiều sự khác biệt, nhưng nó không hoạt động nhiều hơn và trong các thử nghiệm của tôi (sử dụng bản đồ với 1.000.000 int64
khóa ngẫu nhiên và sau đó tạo ra các mảng khóa mười lần với mỗi phương thức), đó là về Nhanh hơn 20% để gán các thành viên của mảng trực tiếp hơn là sử dụng nối thêm.
Mặc dù cài đặt công suất sẽ loại bỏ việc phân bổ lại, việc nối thêm vẫn phải thực hiện thêm công việc để kiểm tra xem bạn đã đạt công suất trên mỗi lần nối hay chưa.
for i, k := range mymap{
. Theo cách đó bạn không cần i ++?
i, k := range mymap
, thì đó i
sẽ là các khóa và k
sẽ là các giá trị tương ứng với các khóa đó trên bản đồ. Điều đó sẽ không thực sự giúp bạn điền vào một lát chìa khóa.
Bạn cũng có thể lấy một mảng các khóa với loại []Value
theo phương thức MapKeys
struct Value
từ gói "phản ánh":
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
?
Một cách tốt hơn để làm điều này sẽ là sử dụng append
:
keys = []int{}
for k := range mymap {
keys = append(keys, k)
}
Ngoài ra, bạn không gặp may mắn, Go Go không phải là một ngôn ngữ rất biểu cảm.
keys = make([]int, 0, len(mymap))
sẽ thoát khỏi phân bổ nhưng tôi hy vọng nó sẽ vẫn chậm hơn.
Tôi đã thực hiện một tiêu chuẩn sơ sài về ba phương pháp được mô tả trong các phản ứng khác.
Rõ ràng việc phân bổ trước lát cắt trước khi kéo các phím nhanh hơn append
ing, nhưng đáng ngạc nhiên, reflect.ValueOf(m).MapKeys()
phương pháp này chậm hơn đáng kể so với phương pháp sau:
❯ 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
Đây là mã: https://play.golang.org/p/Z8O6a2jyfTH (chạy nó trong sân chơi hủy bỏ tuyên bố rằng nó mất quá nhiều thời gian, vì vậy, tốt, chạy nó cục bộ.)
keysAppend
hàm của bạn , bạn có thể đặt dung lượng của keys
mảng với make([]uint64, 0, len(m))
, điều này đã thay đổi đáng kể hiệu năng của hàm đó đối với tôi.
Truy cập 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)
}