Saat melakukan iterasi melalui peta yang dikembalikan dalam kode, yang dikembalikan oleh fungsi topik, kunci tidak muncul secara berurutan.
Bagaimana saya bisa mendapatkan kunci untuk mengatur / mengurutkan peta sehingga kunci-kunci tersebut berurutan dan nilainya sesuai?
Ini kodenya .
Jawaban:
The Go blog: peta Go beraksi memiliki penjelasan yang sangat baik.
Ini versi kode contoh saya yang dimodifikasi: http://play.golang.org/p/dvqcGPYy3-
package main import ( "fmt" "sort" ) func main() { // To create a map as input m := make(map[int]string) m[1] = "a" m[2] = "c" m[0] = "b" // To store the keys in slice in sorted order keys := make([]int, len(m)) i := 0 for k := range m { keys[i] = k i++ } sort.Ints(keys) // To perform the opertion you want for _, k := range keys { fmt.Println("Key:", k, "Value:", m[k]) } }
Keluaran:
Key: 0 Value: b Key: 1 Value: a Key: 2 Value: c
sumber
keys := make([]int, len(m))
dan kemudian masukkan dengan indekskeys[i] = k
alih-alihappend
Menurut spesifikasi Go , urutan iterasi pada peta tidak ditentukan, dan dapat bervariasi antar program berjalan. Dalam praktiknya, tidak hanya tidak ditentukan, itu sebenarnya sengaja diacak. Ini karena dulunya dapat diprediksi, dan pengembang bahasa Go tidak ingin orang mengandalkan perilaku yang tidak ditentukan, jadi mereka sengaja mengacaknya sehingga tidak mungkin mengandalkan perilaku ini.
Apa yang harus Anda lakukan, kemudian, adalah menarik kunci ke dalam irisan, mengurutkannya, dan kemudian menjangkau irisan seperti ini:
var m map[keyType]valueType keys := sliceOfKeys(m) // you'll have to implement this for _, k := range keys { v := m[k] // k is the key and v is the value; do your computation here }
sumber
Semua jawaban di sini sekarang berisi perilaku lama peta. Di Go 1.12+, Anda cukup mencetak nilai peta dan akan diurutkan berdasarkan kunci secara otomatis. Ini telah ditambahkan karena memungkinkan pengujian nilai peta dengan mudah.
func main() { m := map[int]int{3: 5, 2: 4, 1: 3} fmt.Println(m) // In Go 1.12+ // Output: map[1:3 2:4 3:5] // Before Go 1.12 (the order was undefined) // map[3:5 2:4 1:3] }
Baca lebih lanjut di sini .
sumber
Dalam membalas James Craig Burley ini jawabannya . Untuk membuat desain yang bersih dan dapat digunakan kembali, seseorang dapat memilih untuk pendekatan yang lebih berorientasi objek. Metode cara ini dapat dengan aman terikat ke jenis peta yang ditentukan. Bagi saya pendekatan ini terasa lebih bersih dan teratur.
Contoh:
package main import ( "fmt" "sort" ) type myIntMap map[int]string func (m myIntMap) sort() (index []int) { for k, _ := range m { index = append(index, k) } sort.Ints(index) return } func main() { m := myIntMap{ 1: "one", 11: "eleven", 3: "three", } for _, k := range m.sort() { fmt.Println(m[k]) } }
Contoh taman bermain yang diperluas dengan beberapa tipe peta.
Catatan penting
Dalam semua kasus, peta dan potongan yang diurutkan dipisahkan dari saat
for
loop di atas petarange
selesai. Artinya, jika peta diubah setelah logika pengurutan, tetapi sebelum Anda menggunakannya, Anda bisa mendapat masalah. (Bukan utas / Lakukan pengamanan rutin). Jika ada perubahan akses tulis Peta paralel, Anda harus menggunakan mutex di sekitar penulisan danfor
loop yang diurutkan .mutex.Lock() for _, k := range m.sort() { fmt.Println(m[k]) } mutex.Unlock()
sumber
Jika, seperti saya, Anda merasa menginginkan kode pengurutan yang pada dasarnya sama di lebih dari satu tempat, atau hanya ingin menjaga kerumitan kode, Anda dapat memisahkan pengurutan itu sendiri ke fungsi terpisah, di mana Anda meneruskan fungsi yang melakukannya. pekerjaan aktual yang Anda inginkan (yang akan berbeda di setiap situs panggilan, tentu saja).
Diberikan peta dengan tipe kunci
K
dan tipe nilaiV
, yang direpresentasikan sebagai<K>
dan di<V>
bawah, fungsi sortir umum mungkin terlihat seperti template Go-code ini (yang Go versi 1 tidak mendukung apa adanya):/* Go apparently doesn't support/allow 'interface{}' as the value (or /* key) of a map such that any arbitrary type can be substituted at /* run time, so several of these nearly-identical functions might be /* needed for different key/value type combinations. */ func sortedMap<K><T>(m map[<K>]<V>, f func(k <K>, v <V>)) { var keys []<K> for k, _ := range m { keys = append(keys, k) } sort.Strings(keys) # or sort.Ints(keys), sort.Sort(...), etc., per <K> for _, k := range keys { v := m[k] f(k, v) } }
Kemudian panggil dengan peta masukan dan fungsi (mengambil
(k <K>, v <V>)
argumen masukannya) yang dipanggil di atas elemen peta dalam urutan tombol yang diurutkan.Jadi, versi kode dalam jawaban yang diposting oleh Mingu mungkin terlihat seperti ini:
package main import ( "fmt" "sort" ) func sortedMapIntString(m map[int]string, f func(k int, v string)) { var keys []int for k, _ := range m { keys = append(keys, k) } sort.Ints(keys) for _, k := range keys { f(k, m[k]) } } func main() { // Create a map for processing m := make(map[int]string) m[1] = "a" m[2] = "c" m[0] = "b" sortedMapIntString(m, func(k int, v string) { fmt.Println("Key:", k, "Value:", v) }) }
The
sortedMapIntString()
fungsi dapat digunakan kembali untuk setiapmap[int]string
(dengan asumsi urutan yang sama yang diinginkan), menjaga setiap penggunaan hanya dua baris kode.Kerugiannya meliputi:
Bahasa lain memiliki berbagai solusi:
<K>
dan<V>
(untuk menunjukkan tipe untuk kunci dan nilai) terlihat agak familiar, template kode tersebut tidak terlalu berbeda dengan template C ++.range
tipe kelas satu sehingga dapat diganti dengan customordered-range
(sebagai penggantirange
dalam kode asli), saya pikir beberapa bahasa lain menyediakan iterator yang cukup kuat untuk mencapai hal yang sama. benda.sumber
var m map[interface{}]interface{}
sepenuhnya legal. PlaygroundGo apparently doesn't support/allow 'interface{}' as the value (or key) of a map such that any arbitrary type can be substituted at run time
. Jika (selain dengan menggunakanunsafe
atau serupa) Anda dapat menunjukkan bagaimana jenis arbitrer dapat diganti pada waktu proses, sehingga menyediakan satu jenis rutinitas umum, itu akan bagus! (Saya sendiri tidak bisa mengetahuinya, beberapa bulan yang lalu.)Ini memberi Anda contoh kode pada peta pengurutan. Pada dasarnya inilah yang mereka sediakan:
var keys []int for k := range myMap { keys = append(keys, k) } sort.Ints(keys) // Benchmark1-8 2863149 374 ns/op 152 B/op 5 allocs/op
dan inilah yang saya sarankan untuk digunakan sebagai gantinya :
keys := make([]int, 0, len(myMap)) for k := range myMap { keys = append(keys, k) } sort.Ints(keys) // Benchmark2-8 5320446 230 ns/op 80 B/op 2 allocs/op
Kode lengkap dapat ditemukan di Go Playground ini .
sumber