LoginSignup
4
3

More than 5 years have passed since last update.

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

Posted at

引き続き第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でスペースに置換すればおk

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文回せばいいんじゃね

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列目の文字列の異なり

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列目の温度でソートさせるインターフェイスを↓の記事見ながら実装するべさ

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)
    }
}
4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3