golangで言語処理100本ノック(第2章)

引き続き第2章も解いていきます。
第2章はUnixコマンドの基礎ということで、以下のテキストファイルを読み込んで処理を行う内容と
なっています。

```hightemp.txt
高知県	江川崎	41	2013-08-12
埼玉県	熊谷	40.9	2007-08-16
岐阜県	多治見	40.9	2007-08-16
山形県	山形	40.8	1933-07-25
山梨県	甲府	40.7	2013-08-10
和歌山県	かつらぎ	40.6	1994-08-08
静岡県	天竜	40.6	1994-08-04
山梨県	勝沼	40.5	2013-08-10
埼玉県	越谷	40.4	2007-08-16
群馬県	館林	40.3	2007-08-16
群馬県	上里見	40.3	1998-07-04
愛知県	愛西	40.3	1994-08-05
千葉県	牛久	40.2	2004-07-20
静岡県	佐久間	40.2	2001-07-24
愛媛県	宇和島	40.2	1927-07-22
山形県	酒田	40.1	1978-08-03
岐阜県	美濃	40	2007-08-16
群馬県	前橋	40	2001-07-24
千葉県	茂原	39.9	2013-08-11
埼玉県	鳩山	39.9	1997-07-05
大阪府	豊中	39.9	1994-08-08
山梨県	大月	39.9	1990-07-19
山形県	鶴岡	39.9	1978-08-03
愛知県	名古屋	39.9	1942-08-02
```

###10. 行数のカウント
行数をカウントせよ。確認にはwcコマンドを用いよ。

→1行ずつ読み込んだらスライスに入れて、要素数をカウントすればいいんじゃね

```10.go
package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	open := func(path string) []string {
		f, err := os.Open(path)
		if err != nil {
			fmt.Fprintf(os.Stderr, "File %s could not read: %v\n", path, err)
		}
		defer f.Close()

		lines := []string{}
		scanner := bufio.NewScanner(f)
		for scanner.Scan() {
			lines = append(lines, scanner.Text())
		}
		if serr := scanner.Err(); serr != nil {
			fmt.Fprintf(os.Stderr, "File %s scan error: %v\n", path, err)
		}
		return lines
	}
	file := open("../data/hightemp.txt")
	fmt.Println(len(file))

}
```
参考:Go でファイルや標準入力からテキストを一行ずつ読む
http://www.yunabe.jp/tips/golang_readlines.html

###11. タブをスペースに置換

タブ1文字につきスペース1文字に置換せよ．確認にはsedコマンド，trコマンド，もしくはexpandコマンドを用いよ。

→読み込んだのを1行ずつ、strings.Replaceでスペースに置換すればおｋ

```11.go
package main

import (
	"bufio"
	"fmt"
	"os"
	"strings"
)

func main() {
	open := func(path string) []string {
		f, err := os.Open(path)
		if err != nil {
			fmt.Fprintf(os.Stderr, "File %s could not read: %v\n", path, err)
		}
		defer f.Close()

		lines := []string{}
		scanner := bufio.NewScanner(f)
		for scanner.Scan() {
			lines = append(lines, scanner.Text())
		}
		if serr := scanner.Err(); serr != nil {
			fmt.Fprintf(os.Stderr, "File %s scan error: %v\n", path, err)
		}
		return lines
	}

	for _, v := range open("../data/hightemp.txt") {
		fmt.Println(strings.Replace(v, "\t", " ", -1))
	}

}
```

###12. 1列目をcol1.txtに，2列目をcol2.txtに保存

各行の1列目だけを抜き出したものをcol1.txtに，2列目だけを抜き出したものをcol2.txtとしてファイルに保存せよ．確認にはcutコマンドを用いよ。

→1行ずつ読むときにタブでスプリットする。配列の0番目と1番目がそれぞれ1列目と2列目になるのでそれをファイルに書き込めばいいんじゃね

```12.go
package main

import (
	"bufio"
	"fmt"
	"os"
	"strings"
)

func main() {
	arr1, arr2 := []string{}, []string{}

	read := func(path string) []string {
		f, err := os.Open(path)
		if err != nil {
			fmt.Fprintf(os.Stderr, "File %s could not read: %v\n", path, err)
		}
		defer f.Close()

		lines := []string{}
		scanner := bufio.NewScanner(f)
		for scanner.Scan() {
			lines = append(lines, scanner.Text())
		}
		if serr := scanner.Err(); serr != nil {
			fmt.Fprintf(os.Stderr, "File %s scan error: %v\n", path, err)
		}
		return lines
	}

	for _, v := range read("../data/hightemp.txt") {
		tmp := strings.Fields(v)
		arr1 = append(arr1, tmp[0])
		arr2 = append(arr2, tmp[1])
	}

	write := func(text string, data []string) {
		f, err := os.Create(text)
		if err != nil {
			panic(err)
		}
		w := bufio.NewWriter(f)
		for _, v := range data {
			fmt.Fprint(w, v, "\n")
		}
		w.Flush()
	}

	write("col1.txt", arr1)
	write("col2.txt", arr2)

}
```

###13. col1.txtとcol2.txtをマージ

12で作ったcol1.txtとcol2.txtを結合し，元のファイルの1列目と2列目をタブ区切りで並べたテキストファイルを作成せよ。確認にはpasteコマンドを用いよ。

→col1.txt、col2.txtをそれぞれ読み取って、2個のスライスを引数にファイルに書けばいいんじゃね

```13.go
package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	arr1, arr2 := []string{}, []string{}

	read := func(path string) []string {
		f, err := os.Open(path)
		if err != nil {
			fmt.Fprintf(os.Stderr, "File %s could not read: %v\n", path, err)
		}
		defer f.Close()

		lines := []string{}
		scanner := bufio.NewScanner(f)
		for scanner.Scan() {
			lines = append(lines, scanner.Text())
		}
		if serr := scanner.Err(); serr != nil {
			fmt.Fprintf(os.Stderr, "File %s scan error: %v\n", path, err)
		}
		return lines
	}

	arr1 = read("col1.txt")
	arr2 = read("col2.txt")

	write := func(row1, row2 []string, text string) {
		f, err := os.Create(text)
		if err != nil {
			panic(err)
		}
		w := bufio.NewWriter(f)
		for i, _ := range row1 {
			fmt.Fprint(w, row1[i], "\t", row2[i], "\n")
		}
		w.Flush()
	}

	write(arr1, arr2, "merge.txt")

}
```

###14. 先頭からN行を出力

自然数Nをコマンドライン引数などの手段で受け取り，入力のうち先頭のN行だけを表示せよ．確認にはheadコマンドを用いよ。

→N行分までFor文で出力さすればいいんじゃね

```14.go
package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
)

func main() {

	read := func(path string) []string {
		f, err := os.Open(path)
		if err != nil {
			fmt.Fprintf(os.Stderr, "File %s could not read: %v\n", path, err)
		}
		defer f.Close()

		lines := []string{}
		scanner := bufio.NewScanner(f)
		for scanner.Scan() {
			lines = append(lines, scanner.Text())
		}
		if serr := scanner.Err(); serr != nil {
			fmt.Fprintf(os.Stderr, "File %s scan error: %v\n", path, err)
		}
		return lines
	}

	text := read("../data/hightemp.txt")
	n, _ := strconv.Atoi(os.Args[1])
	for i := 0; i < n; i++ {
		fmt.Println(text[i])
	}

}
```

###15. 末尾のN行を出力

自然数Nをコマンドライン引数などの手段で受け取り，入力のうち末尾のN行だけを表示せよ．確認にはtailコマンドを用いよ。

→末尾だからN行目以降、NからFor文回せばいいんじゃね

```golang:15.go
package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
)

func main() {

	read := func(path string) []string {
		f, err := os.Open(path)
		if err != nil {
			fmt.Fprintf(os.Stderr, "File %s could not read: %v\n", path, err)
		}
		defer f.Close()

		lines := []string{}
		scanner := bufio.NewScanner(f)
		for scanner.Scan() {
			lines = append(lines, scanner.Text())
		}
		if serr := scanner.Err(); serr != nil {
			fmt.Fprintf(os.Stderr, "File %s scan error: %v\n", path, err)
		}
		return lines
	}

	text := read("../data/hightemp.txt")
	n, _ := strconv.Atoi(os.Args[1])
	for i := len(text) - n; i < len(text); i++ {
		fmt.Println(text[i])
	}

}
```

###16. ファイルをN分割する

自然数Nをコマンドライン引数などの手段で受け取り，入力のファイルを行単位でN分割せよ．同様の処理をsplitコマンドで実現せよ。

→行数 / N の値で割り切れたときにファイルに書けばいいんじゃね。
24行を4分割すると、24 / 4 = 6 だから、For文回したときに6で割り切れた時にファイルに書けば
6行ずつファイルに4分割されんじゃね？

```16.go
package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
)

func main() {

	read := func(path string) []string {
		f, err := os.Open(path)
		if err != nil {
			fmt.Fprintf(os.Stderr, "File %s could not read: %v\n", path, err)
		}
		defer f.Close()

		lines := []string{}
		scanner := bufio.NewScanner(f)
		for scanner.Scan() {
			lines = append(lines, scanner.Text())
		}
		if serr := scanner.Err(); serr != nil {
			fmt.Fprintf(os.Stderr, "File %s scan error: %v\n", path, err)
		}
		return lines
	}

	write := func(row []string, text string) {
		f, err := os.Create(text)
		if err != nil {
			panic(err)
		}
		w := bufio.NewWriter(f)
		for _, v := range row {
			fmt.Fprint(w, v, "\n")
		}
		w.Flush()
	}

	text := read("../data/hightemp.txt")
	n, _ := strconv.Atoi(os.Args[1])
	splitcnt := len(text) / n

	tmp := []string{}
	for i := 1; i <= len(text); i++ {
		tmp = append(tmp, text[i-1])
		if i%splitcnt == 0 {
			write(tmp, strconv.Itoa(i)+".txt")
			tmp = []string{}
		}
	}

}
```

###17. １列目の文字列の異なり

1列目の文字列の種類（異なる文字列の集合）を求めよ．確認にはsort, uniqコマンドを用いよ。

→mapにkeyに1列目を入れてって集合を出せばいいんじゃね

```17.go
package main

import (
	"bufio"
	"fmt"
	"os"
	"strings"
)

func main() {

	read := func(path string) []string {
		f, err := os.Open(path)
		if err != nil {
			fmt.Fprintf(os.Stderr, "File %s could not read: %v\n", path, err)
		}
		defer f.Close()

		lines := []string{}
		scanner := bufio.NewScanner(f)
		for scanner.Scan() {
			lines = append(lines, scanner.Text())
		}
		if serr := scanner.Err(); serr != nil {
			fmt.Fprintf(os.Stderr, "File %s scan error: %v\n", path, err)
		}
		return lines
	}

	makemap := func(arr []string) map[string]bool {
		tmp := make(map[string]bool)
		for _, v := range arr {
			_, ok := tmp[v]
			if ok == false {
				tmp[v] = true
			}
		}
		return tmp
	}

	txt := read("../data/hightemp.txt")
	var row1 = []string{}
	for _, v := range txt {
		tmp := strings.Fields(v)
		row1 = append(row1, tmp[0])
	}
	for i, _ := range makemap(row1) {
		fmt.Println(i)
	}
}
```

###18. 各行を3コラム目の数値の降順にソート

各行を3コラム目の数値の逆順で整列せよ（注意: 各行の内容は変更せずに並び替えよ）。確認にはsortコマンドを用いよ（この問題はコマンドで実行した時の結果と合わなくてもよい）。

→1列目～4列目をひとまず構造体にセットして、3列目の温度でソートさせるインターフェイスを↓の記事見ながら実装するべさ

https://qiita.com/Jxck_/items/fb829b818aac5b5f54f7

```18.go
package main

import (
	"bufio"
	"fmt"
	"os"
	"sort"
	"strconv"
	"strings"
)

type Hightemp struct {
	pref string
	town string
	temp float64
	date string
}

type ByTemp []Hightemp

func (a ByTemp) Len() int {
	return len(a)
}

func (a ByTemp) Swap(i, j int) {
	a[i], a[j] = a[j], a[i]
}

func (a ByTemp) Less(i, j int) bool {
	return a[i].temp < a[j].temp
}

func main() {

	read := func(path string) []string {
		f, err := os.Open(path)
		if err != nil {
			fmt.Fprintf(os.Stderr, "File %s could not read: %v\n", path, err)
		}
		defer f.Close()

		lines := []string{}
		scanner := bufio.NewScanner(f)
		for scanner.Scan() {
			lines = append(lines, scanner.Text())
		}
		if serr := scanner.Err(); serr != nil {
			fmt.Fprintf(os.Stderr, "File %s scan error: %v\n", path, err)
		}
		return lines
	}

	txt := read("../data/hightemp.txt")
	arr := []Hightemp{}
	for _, v := range txt {
		tmp := strings.Fields(v)
		ondo, _ := strconv.ParseFloat(tmp[2], 64)
		tmp1 := Hightemp{tmp[0], tmp[1], ondo, tmp[3]}
		arr = append(arr, tmp1)
	}
	sort.Sort(ByTemp(arr))
	for _, v := range arr {
		fmt.Printf("%v\t%v\t%v\t%v\n", v.pref, v.town, v.temp, v.date)
	}
}
```

###19. 各行の1コラム目の文字列の出現頻度を求め，出現頻度の高い順に並べる

各行の1列目の文字列の出現頻度を求め，その高い順に並べて表示せよ。確認にはcut, uniq, sortコマンドを用いよ。

→1列目の文字列とカウント回数のmapを作成して構造体にいれてソートさせればいいんじゃね？
18と同じようなことを出現回数でやればよくね。

```19.go
package main

import (
	"bufio"
	"fmt"
	"os"
	"sort"
	"strings"
)

type Hightemp struct {
	pref string
	cnt  int
}

type ByCnt []Hightemp

func (a ByCnt) Len() int {
	return len(a)
}

func (a ByCnt) Swap(i, j int) {
	a[i], a[j] = a[j], a[i]
}

func (a ByCnt) Less(i, j int) bool {
	return a[i].cnt > a[j].cnt
}

func main() {

	read := func(path string) []string {
		f, err := os.Open(path)
		if err != nil {
			fmt.Fprintf(os.Stderr, "File %s could not read: %v\n", path, err)
		}
		defer f.Close()

		lines := []string{}
		scanner := bufio.NewScanner(f)
		for scanner.Scan() {
			lines = append(lines, scanner.Text())
		}
		if serr := scanner.Err(); serr != nil {
			fmt.Fprintf(os.Stderr, "File %s scan error: %v\n", path, err)
		}
		return lines
	}

	makemap := func(arr []string) map[string]int {
		tmp := make(map[string]int)
		for _, v := range arr {
			_, ok := tmp[v]
			if ok == false {
				tmp[v] = 1
			} else {
				tmp[v] = tmp[v] + 1
			}
		}
		return tmp
	}

	txt := read("../data/hightemp.txt")
	var row1 = []string{}
	for _, v := range txt {
		tmp := strings.Fields(v)
		row1 = append(row1, tmp[0])
	}

	arr := []Hightemp{}
	for i, v := range makemap(row1) {
		tmp := Hightemp{i, v}
		arr = append(arr, tmp)
	}
	sort.Sort(ByCnt(arr))
	for _, v := range arr {
		fmt.Printf("%v %v\n", v.pref, v.cnt)
	}
}
```