80 lines
1.2 KiB
Go
80 lines
1.2 KiB
Go
|
package main
|
||
|
|
||
|
import (
|
||
|
"bufio"
|
||
|
"fmt"
|
||
|
"os"
|
||
|
"strings"
|
||
|
"sync"
|
||
|
)
|
||
|
|
||
|
/*
|
||
|
|
||
|
@Ref: https://livebook.manning.com/book/go-in-practice/chapter-3/65
|
||
|
1. --reac flag is able to do the race detection
|
||
|
2. How to use scanner to split the word in a file
|
||
|
3. sync.Mutex usage
|
||
|
*/
|
||
|
|
||
|
func main() {
|
||
|
|
||
|
wg := sync.WaitGroup{}
|
||
|
|
||
|
w := newWords()
|
||
|
for _, file := range os.Args[1:] {
|
||
|
wg.Add(1)
|
||
|
go func(filename string) {
|
||
|
tallyWords(filename, w)
|
||
|
wg.Done()
|
||
|
}(file)
|
||
|
|
||
|
}
|
||
|
|
||
|
wg.Wait()
|
||
|
|
||
|
fmt.Println("Words that appear more than once:")
|
||
|
for word, count := range w.found {
|
||
|
if count > 1 {
|
||
|
fmt.Printf("%s: %d\n", word, count)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
type words struct {
|
||
|
sync.Mutex
|
||
|
found map[string]int
|
||
|
}
|
||
|
|
||
|
func newWords() *words {
|
||
|
return &words{found: make(map[string]int)}
|
||
|
}
|
||
|
|
||
|
func (w *words) add(word string, n int) {
|
||
|
w.Lock()
|
||
|
defer w.Unlock()
|
||
|
|
||
|
count, ok := w.found[word]
|
||
|
if !ok {
|
||
|
w.found[word] = n
|
||
|
return
|
||
|
}
|
||
|
w.found[word] = count + n
|
||
|
}
|
||
|
|
||
|
func tallyWords(filename string, dist *words) error {
|
||
|
file, err := os.Open(filename)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
defer file.Close()
|
||
|
|
||
|
scanner := bufio.NewScanner(file)
|
||
|
scanner.Split(bufio.ScanWords)
|
||
|
for scanner.Scan() {
|
||
|
word := strings.ToLower(scanner.Text())
|
||
|
dist.add(word, 1)
|
||
|
}
|
||
|
return scanner.Err()
|
||
|
}
|