map

  • map 是 Go 提供的另外一种集合:
    • 它可以将 key 映射到 value。
    • 可快速通过 key 找到对应的 value
    • 它的 key 几乎可以是任何类型

声明 map

  • 声明 map,必须指定 key 和 value 的类型:

map - 图1

  1. package main
  2. import "fmt"
  3. func main() {
  4. temperature := map[string]int{
  5. "Earth": 15,
  6. "Mars": -65,
  7. }
  8. temp := temperature["Earth"]
  9. fmt.Printf("On average the Earth is %vº C.\n", temp)
  10. temperature["Earth"] = 16
  11. temperature["Venus"] = 464
  12. fmt.Println(temperature)
  13. moon := temperature["Moon"]
  14. fmt.Println(moon)
  15. if moon, ok := temperature["Moon"]; ok {
  16. fmt.Printf("On average the moon is %vº C.\n", moon)
  17. } else {
  18. fmt.Println("Where is the moon?")
  19. }
  20. _, ok := temperature["Earth"]
  21. fmt.Println(ok)
  22. delete(temperature, "Earth")
  23. }

逗号与 ok 写法

  1. if moon, ok := temperature["Moon"]; ok {
  2. fmt.Printf("On average the moon is %vº C.\n", moon)
  3. } else {
  4. fmt.Println("Where is the moon?")
  5. }

map 不会被复制

  • 数组、int、float64 等类型在赋值给新变量或传递至函数/方法的时候会创建相应的副本
  • 但 map 不会
  1. package main
  2. import "fmt"
  3. func main() {
  4. planets := map[string]string{
  5. "Earth": "Sector ZZ9",
  6. "Mars": "Sector ZZ9",
  7. }
  8. planetsMarkII := planets
  9. planets["Earth"] = "whoops"
  10. fmt.Println(planets)
  11. fmt.Println(planetsMarkII)
  12. delete(planets, "Earth")
  13. fmt.Println(planetsMarkII)
  14. }

使用 make 函数对 map 进行预分配

  • 除非你使用复合字面值来初始化 map,否则必须使用内置的 make 函数来为 map 分配空间。
  • 创建 map 时,make 函数可接受一个或两个参数
    • 第二个参数用于为指定数量的 key 预先分配空间
  • 使用 make 函数创建的 map 的初始长度为 0

使用 map 作计数器

  1. package main
  2. import "fmt"
  3. func main() {
  4. temperatures := []float64{
  5. -28.0, 32.0, -31.0, -29.0, -23.0, -29.0, -28.0, -33.0,
  6. }
  7. frequency := make(map[float64]int)
  8. for _, t := range temperatures {
  9. frequency[t]++
  10. }
  11. for t, num := range frequency {
  12. fmt.Printf("%+.2f occurs %d times\n", t, num)
  13. }

使用 map 和 slice 实现数据分组

  1. package main
  2. import (
  3. "fmt"
  4. "math"
  5. )
  6. func main() {
  7. temperatures := []float64{
  8. -28.0, 32.0, -31.0, -29.0, -23.0, -29.0, -28.0, -33.0,
  9. }
  10. groups := make(map[float64][]float64)
  11. for _, t := range temperatures {
  12. g := math.Trunc(t/10) * 10
  13. groups[g] = append(groups[g], t)
  14. }
  15. for g, temperatures := range groups {
  16. fmt.Printf("%v: %v\n", g, temperatures)
  17. }
  18. }

将 map 用作 set

  • Set 这种集合与数组类似,但元素不会重复
  • Go 语言里没有提供 set 集合
  1. package main
  2. import (
  3. "fmt"
  4. "sort"
  5. )
  6. func main() {
  7. var temperatures = []float64{
  8. -28.0, 32.0, -31.0, -29.0, -23.0, -29.0, -28.0, -33.0,
  9. }
  10. set := make(map[float64]bool)
  11. for _, t := range temperatures {
  12. set[t] = true
  13. }
  14. if set[-28.0] {
  15. fmt.Println("set member")
  16. }
  17. fmt.Println(set)
  18. unique := make([]float64, 0, len(set))
  19. for t := range set {
  20. unique = append(unique, t)
  21. }
  22. sort.Float64s(unique)
  23. fmt.Println(unique)
  24. }

作业题

  • 编写一个函数:
    • 它可以统计文本字符串中不同单词的出现频率,并返回一个词频 map。
    • 该函数需要将文本转换为小写字母并移除包含的标点符号
    • strings 包中的 Fields、ToLower、Trim 函数应该对此有所帮助
    • 使用该函数统计下文中各单词出现的频率,打印出现不止一次的单词和词频:
      As far as eye could reach he saw nothing but the stems of the great plants about him receding in the violet shade, and far overhead the multiple transparency of huge leaves filtering the sunshine to the solemn splendour of twilight in which he walked. Whenever he felt able he ran again; the ground continued soft and springy, covered with the same resilient weed which was the first thing his hands had touched in Malacandra. Once or twice a small red creature scuttled across his path, but otherwise there seemed to be no life stirring in the wood; nothing to fear—except the fact of wandering unprovisioned and alone in a forest of unknown vegetation thousands or millions of miles beyond the reach or knowledge of man.
  1. package main
  2. import (
  3. "fmt"
  4. "strings"
  5. )
  6. func countWords(text string) map[string]int {
  7. words := strings.Fields(strings.ToLower(text))
  8. frequency := make(map[string]int, len(words))
  9. for _, word := range words {
  10. word = strings.Trim(word, `.,"-`)
  11. frequency[word]++
  12. }
  13. return frequency
  14. }
  15. func main() {
  16. text := `As far as eye could reach he saw nothing but the stems of the
  17. great plants about him receding in the violet shade, and far overhead
  18. the multiple transparency of huge leaves filtering the sunshine to the
  19. solemn splendour of twilight in which he walked. Whenever he felt able
  20. he ran again; the ground continued soft and springy, covered with the
  21. same resilient weed which was the first thing his hands had touched in
  22. Malacandra. Once or twice a small red creature scuttled across his
  23. path, but otherwise there seemed to be no life stirring in the wood;
  24. nothing to fear —- except the fact of wandering unprovisioned and alone
  25. in a forest of unknown vegetation thousands or millions of miles
  26. beyond the reach or knowledge of man.`
  27. frequency := countWords(text)
  28. for word, count := range frequency {
  29. if count > 1 {
  30. fmt.Printf("%d %v\n", count, word)
  31. }
  32. }
  33. }