23. Map — Solusi PR

File solusi .go ada di exercises/23/homework/solutions/.

Soal 1 — Catatan pemain

Soal. Buat map pemain, dan cetak setiap kunci dan nilai secara terurut.

Cara berpikir. Literal dengan empat kunci. Lalu tiga langkah dari bab tadi: kumpulkan kunci, urutkan, ulangi.

Solusi yang dikerjakan.

package main

import (
    "fmt"
    "slices"
)

func main() {
    player := map[string]string{
        "name":  "Keiko",
        "class": "Mage",
        "level": "7",
        "alive": "true",
    }

    keys := []string{}
    for key := range player {
        keys = append(keys, key)
    }
    slices.Sort(keys)

    for _, key := range keys {
        fmt.Println(key, player[key])
    }
}

Output:

alive true
class Mage
level 7
name Keiko

Tanpa pengurutan, baris-barisnya akan keluar dengan urutan berbeda di setiap kali jalan.

Kesalahan umum.

  • Menulis player.name alih-alih player["name"]. Map tidak punya penulisan dengan titik.
  • Menulis player[name] tanpa tanda kutip. name tanpa tanda kutip adalah variabel, jadi Go mencari variabel bernama name, dan berhenti dengan undefined: name kalau tidak ada.
  • Menulis "level": 7 di map ini. Go berhenti, karena 7 bukan string.

Soal 2 — Berat inventaris

Soal. Jumlahkan nilai-nilai dalam map.

Cara berpikir. Simpan total berjalan, seperti di Bab 22. Kuncinya tidak dibutuhkan, jadi tulis _. Urutan tidak berpengaruh pada jumlah, jadi tidak perlu diurutkan.

Solusi yang dikerjakan.

package main

import "fmt"

func main() {
    inventory := map[string]float64{
        "sword":  3.5,
        "shield": 5.0,
        "potion": 0.2,
        "map":    0.1,
        "coins":  0.05,
    }

    total := 0.0
    for _, weight := range inventory {
        total += weight
    }

    fmt.Printf("Total weight: %.2f\n", total)
}

Output:

Total weight: 8.85

total := 0.0 membuat float64, agar sesuai dengan nilai-nilainya. Dengan total := 0, tipenya int, dan total += weight berhenti dengan error mismatched types.

Kesalahan umum.

  • Menulis for weight := range inventory. Dengan satu variabel, range pada map memberikan kunci, bukan nilai. weight akan berisi "sword", dan total += weight tidak bisa dikompilasi.

Soal 3 — Pencarian aman

Soal. lookup mengembalikan nilainya atau "(not found)".

Cara berpikir. Minta dua nilai, dan periksa ok. Kembalikan teks pengganti kalau nilainya false. Kalau tidak, kembalikan nilainya.

Solusi yang dikerjakan.

package main

import "fmt"

func lookup(player map[string]string, key string) string {
    value, ok := player[key]
    if !ok {
        return "(not found)"
    }
    return value
}

func main() {
    player := map[string]string{"name": "Keiko", "class": "Mage"}

    fmt.Println(lookup(player, "name"))  // Keiko
    fmt.Println(lookup(player, "email")) // (not found)

    key := "class"
    fmt.Println(lookup(player, key)) // Mage
}

Kesalahan umum.

  • Memeriksa nilainya, bukan ok:
func lookup(player map[string]string, key string) string {
    if player[key] == "" {
        return "(not found)"
    }
    return player[key]
}

Kunci yang tidak ada memberikan "", jadi ini terlihat berjalan. Tetapi kunci yang ada dan memang berisi "" dilaporkan tidak ditemukan. Hanya ok yang bisa membedakan keduanya.

Tantangan — Frekuensi kata

Soal. Hitung kemunculan setiap kata dalam slice.

Cara berpikir. Telusuri slice sekali. Untuk setiap kata, tambahkan 1 ke jumlahnya. Saat sebuah kata pertama kali terlihat, kata itu belum ada di map, dan kunci yang tidak ada memberikan 0. Jadi 0 ditambah 1 menjadi 1, dan tidak perlu kasus khusus:

counts := map[string]int{}
for _, word := range words {
    counts[word]++
}

Lalu urutkan kuncinya untuk dicetak.

Solusi yang dikerjakan.

package main

import (
    "fmt"
    "slices"
)

func main() {
    words := []string{"apple", "banana", "apple", "cherry", "apple", "banana"}

    counts := map[string]int{}
    for _, word := range words {
        counts[word]++
    }

    keys := []string{}
    for word := range counts {
        keys = append(keys, word)
    }
    slices.Sort(keys)

    for _, word := range keys {
        fmt.Println(word, counts[word])
    }
}

Output:

apple 3
banana 2
cherry 1

Kesalahan umum.

  • Langsung mengulang counts untuk mencetak. Baris-barisnya akan keluar dengan urutan acak.
  • Memeriksa ok sebelum menambah. Itu berjalan, tetapi butuh empat baris untuk hal yang dikerjakan counts[word]++ dalam satu baris, karena nilai nol sudah menjadi awal yang tepat.

Selesai?

Berikutnya, Bekerja dengan slice memberimu alat siap pakai untuk mengurutkan, membalik, dan mencari, dan bab terakhir Bagian 5 memecah kode ke beberapa file memakai package. Setelah itu, mini-proyek Bagian 5, Petualangan Teks, menggabungkan map, slice, fungsi, dan package menjadi dunia game yang kecil.