Map (雜湊表)

它是無排序的鍵(key) / 值(value) 群,所有的鍵值獨一無二。 無論 map 有多大 ,都能透過 key 來進行讀取、修改、刪除。

簡介

// 用 make 建構 Map
ages := make(map[string]int)

// 用 map key work 建構
ages := map[string]int{
  "alice": 31,
  "charlie": 34
}

// 上方亦可寫成
ages := make(map[string]int)
ages["alice"] = 31
ages["charlie"] = 34

// 使用 delete func 來刪除特定值
delete(ages, "alice") // 傳入 map 與想要刪除的 key

// 如果傳入無效的 key 值,會回傳該 value 型別的預設值
ages["bob"] = ages["bob"] + 1 // 等號後方的 ages["bob"] 的值為 0 (int 的預設值)

// 上方也可以寫成
ages["bob"] += 1
ages["bob"]++
  • map 的 value 不是變數,我們無法取得它的位址,原因之一是因為,map 是很有可能會增長的,隨著增長的過程會導致現有的元素重新計算而將 value 放在不同的位址上。
  • map 的迭代是沒有順序的

透過 return value 來判斷 key 是否有值

age, ok := ages["bob"]
if !ok { /* "bob" is not a key in this map; age == 0 */ }

兩個 map 的比較

func equal(x, y map[string]int): bool{
  if len(x) != len(y){
    return false
  }
  for k, xv := range x{
    if yv, ok := y[k]; !ok || yv !=xv {
      return false
    }
  }
  return true
}

運用 map 特性來設計出 set

下面的程式碼利用了 map key 值不會相同的原理,來達到 seen 這個 map 的結構變成一個 String Set 。

  func main(){
    seen := make(map[string]bool)
    input := bufio.NewScanner(os.Stdin)
    for input.Scan(){
      line := input.Text()
      if !seen[line]{
        seen[line] = true
        fmt.Println(line)
      }
    }

    if err := input.Err(); err != nil{
      fmt.Fprintf(os.Stderr, "dedup: %v\n", err)
      os.Exit(1)
    }
  }

如何使用 slice or set 當作 key ?

map 的 key 值必須為可比較的狀態,所以 slice or map 並不能夠當作 key 。 但我們可以透過某些方式讓這個方式成為可能。

下面的程式碼目的是想要計算 slice 被 Add 的次數。

var m = make(map[string]int)

func k(list []string) string  { return fmt.Sprintf("%q", list) }
func Add(list []string)       { m[k(list)]++ }
func Count(list [string]) int { return m[k(list)] }