ch4-03 done

Fixes #59
This commit is contained in:
chai2010 2015-12-29 21:09:07 +08:00
parent 1da223e2d1
commit c206b7a513

View File

@ -191,4 +191,106 @@ func Add(list []string) { m[k(list)]++ }
func Count(list []string) int { return m[k(list)] }
```
TODO
使用同樣的技術可以處理任何不可比較的key類型而不僅僅是slice類型。它對於想使用自定義key比較函數的時候也很有用例如在比較字符串的時候忽略大小寫。同時輔助函數k(x)也不一定是字符串類型,它可以返迴任何可比較的類型,例如整數、數組或結構體等。
這是map的另一個例子下面的程序用於統計輸入中每個Unicode碼點出現的次數。雖然Unicode全部碼點的數量鉅大但是出現在特點文檔中的字符併沒有多少使用map可以用比較自然的方式來跟蹤那些見過字符次數。
```Go
gopl.io/ch4/charcount
// Charcount computes counts of Unicode characters.
package main
import (
"bufio"
"fmt"
"io"
"os"
"unicode"
"unicode/utf8"
)
func main() {
counts := make(map[rune]int) // counts of Unicode characters
var utflen [utf8.UTFMax + 1]int // count of lengths of UTF-8 encodings
invalid := 0 // count of invalid UTF-8 characters
in := bufio.NewReader(os.Stdin)
for {
r, n, err := in.ReadRune() // returns rune, nbytes, error
if err == io.EOF {
break
}
if err != nil {
fmt.Fprintf(os.Stderr, "charcount: %v\n", err)
os.Exit(1)
}
if r == unicode.ReplacementChar && n == 1 {
invalid++
continue
}
counts[r]++
utflen[n]++
}
fmt.Printf("rune\tcount\n")
for c, n := range counts {
fmt.Printf("%q\t%d\n", c, n)
}
fmt.Print("\nlen\tcount\n")
for i, n := range utflen {
if i > 0 {
fmt.Printf("%d\t%d\n", i, n)
}
}
if invalid > 0 {
fmt.Printf("\n%d invalid UTF-8 characters\n", invalid)
}
}
```
ReadRune方法執行UTF-8解碼併返迴三個值解碼的rune字符的值字符UTF-8編碼後的長度和一個錯誤值。我們可預期的錯誤值隻有對應文件結尾的io.EOF。如果輸入的是無效的UTF-8編碼的字符返迴的將是unicode.ReplacementChar無效字符併且編碼長度是1。
charcount程序同時打印不同UTF-8編碼長度的字符數目。對此map併不是一個合適的數據結構因爲UTF-8編碼的長度總是從1到utf8.UTFMax最大是4個字節使用數組將更有效。
作爲一個實驗我們用charcount程序對本身的字符進行了統計。雖然大部分是英語但是也有一些非ASCII字符。下面是排名前10的非ASCII字符
![](../images/ch4-xx-01.png)
下面是不同UTF-8編碼長度的字符的數目
```
len count
1 765391
2 60
3 70
4 0
```
Map的value類型也可以是一個聚合類型比如是一個map或slice。在下面的代碼中圖graph的key類型是一個字符串value類型map[string]bool代表一個字符串集合。從概念上將graph將一個字符串類型的key映射到一組相關的字符串集合它們指向新的graph的key。
```Go
gopl.io/ch4/graph
var graph = make(map[string]map[string]bool)
func addEdge(from, to string) {
edges := graph[from]
if edges == nil {
edges = make(map[string]bool)
graph[from] = edges
}
edges[to] = true
}
func hasEdge(from, to string) bool {
return graph[from][to]
}
```
其中addEdge函數惰性初始化map是一個慣用方式也就是説在每個值首次作爲key是才初始化。addEdge函數顯示了如何讓map的零值也能正常工作卽使from到to的邊不存在graph[from][to]依然可以返迴一個有意義的結果。
**練習 4.8** 脩改charcount程序使用unicode.IsLetter等相關的函數統計字母、數字等Unicode中不同的字符類别。
**練習 4.9** 編寫一個程序wordfreq程序報告輸入文本中每個單詞出現的頻率。在第一次調用Scan前先調用input.Split(bufio.ScanWords)函數,這樣可以按單詞而不是按行輸入。