引き続きGo公式のチュートリアル「A Tour of Go」を読み進めています。その中に練習問題がいくつか用意されています。当記事は、Mapに関する練習問題「Exercise: Maps」を解いた記録です。
コード
package main
import (
"golang.org/x/tour/wc"
)
func WordCount(s string) map[string]int {
ret := make(map[string]int)
left := 0
for i, val := range s {
// 空白を見つけてsの left ~ i-1番目まで(i番目は空白) の単語の値をインクリメントして
// leftを更新する。leftの更新時に+1 しているのは空白をスキップするため
if ' ' == val {
ret[s[left:i]]++
left = i + 1
// 最後の単語だけ特別扱い
} else if i == len(s)-1 {
ret[s[left:]]++
}
}
return ret
}
func main() {
wc.Test(WordCount)
}
解説
コードとコメントを見ていただけると大体わかると思いますが、できる範囲で解説を書きます。
for i, val := range s
forを使って文字列sを先頭から末尾まで、1文字ずつ巡回します。iはindexで、valはsのi番目の文字です。
ret[s[left:i]]++
ここが肝だと思います。各単語の出現回数を記録します。retはreturnするmapです。WordCountの先頭で定義しています。
s[left:i]
retの中身であるこれはスライスで、文字列sのleft文字目からi-1文字目までの部分文字列を表します。iが指している文字は含まれません。この時iは空白を表しているので、単語の先頭から末尾までの部分列を取得することができます。
// 最後の単語だけ特別扱い
} else if i == len(s) - 1 {
ret[s[left:]]++
}
これは、iが末尾の文字を指している時は特別に扱う処理です。末尾だけ特別な処理が必要な理由は、スライスが右端を含まないからです。
例えば文字列"Don't repeat your self"を考えます。"your"までは順調に分解できますが、"self"を切り出したい時、iはfを指しているのでそのままスライスしようとすると、"sel"が切り出されてしまいます。
当然切り出したいのは"sel"ではなく"self"なので、特別に処理を設けるに至った次第です。
:の右側に何も書かないと、末尾まで切り出してくれます。
最後に
else if の処理が綺麗じゃないので、良い書き方があったら教えていただけると嬉しいです。
今のところGoって完結でわかりやすい言語だなーと思っております。