mirror of
https://github.com/gopl-zh/gopl-zh.github.com.git
synced 2024-11-24 15:18:57 +00:00
parent
1da223e2d1
commit
c206b7a513
104
ch4/ch4-03.md
104
ch4/ch4-03.md
@ -191,4 +191,106 @@ func Add(list []string) { m[k(list)]++ }
|
|||||||
func Count(list []string) int { return 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)函數,這樣可以按單詞而不是按行輸入。
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user