Gaucheで言語処理100本ノック2015 第2章: UNIXコマンドの基礎


# 第2章: UNIXコマンドの基礎

hightemp.txtは，日本の最高気温の記録を「都道府県」「地点」「℃」「日」のタブ区切り形式で格納したファイルである．以下の処理を行うプログラムを作成し，hightemp.txtを入力ファイルとして実行せよ．さらに，同様の処理をUNIXコマンドでも実行し，プログラムの実行結果を確認せよ．

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

```scm
(use file.util)

(print (length (file->string-list "hightemp.txt")))
```

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

```scm
(use file.util)
(use srfi-13)

(print (string-map (lambda (x) (if (eqv? x #\tab) #\space x))
                   (file->string "hightemp.txt")))
```

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

```scm
(use file.util)

(let* ((rows (map (lambda (x) (string-split x #\tab))
                              (file->string-list "hightemp.txt")))
       (col1 (map car rows))
       (col2 (map cadr rows)))
      (call-with-output-file "col1.txt"
                             (lambda (p) (display (string-join col1 "\n") p)))
      (call-with-output-file "col2.txt"
                             (lambda (p) (display (string-join col2 "\n") p))))
```

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

```scm
(use file.util)
(use srfi-1)

(let ((col1 (file->string-list "col1.txt"))
      (col2 (file->string-list "col2.txt")))
     (print (string-join (map (lambda (x) (string-join x "\t"))
                              (zip col1 col2))
                         "\n")))
```

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

```scm
(use file.util)

(let ((n (string->number (car *argv*))))
     (print (string-join (take (file->string-list "hightemp.txt") n)
                         "\n")))
```

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

```scm
(use file.util)

(let ((n (string->number (car *argv*))))
     (print (string-join (take-right (file->string-list "hightemp.txt") n)
                         "\n")))
```

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

```scm
(use file.util)
(use gauche.sequence)

(let* ((n (string->number (car *argv*)))
       (ls (file->string-list "hightemp.txt"))
       (m (if (eq? (remainder (length ls) n) 0)
              (quotient (length ls) n)
              (+ (quotient (length ls) n) 1))))
      (for-each-with-index
        (lambda (i x)
                (call-with-output-file
                  (string-append (number->string i) ".txt")
                  (lambda (p) (display (string-join x "\n") p))))
        (slices ls m)))
```

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

```scm
(use file.util)

(let* ((rows (map (lambda (x) (string-split x #\tab))
                              (file->string-list "hightemp.txt")))
       (col1 (map car rows)))
      (print (string-join (delete-duplicates col1) "\n")))
```

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

```scm
(use file.util)

(let* ((xs (file->string-list "hightemp.txt"))
       (ys (sort xs
                 <
                 (lambda (x) (string->number
                               (caddr
                                 (string-split x #\tab)))))))
      (print (string-join ys "\n")))
```

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

```scm
(use file.util)

(let* ((xs (file->string-list "hightemp.txt"))
       (ys (make-hash-table 'string=?))
       (zs
         (begin
           (for-each (lambda (x)
                       (hash-table-push! ys
                                         (car (string-split x #\tab))
                                         x))
           xs)
           (fold append '()
                        (sort (hash-table-values ys)
                              <
                              (lambda (z) (length z)))))))
       (print (string-join zs "\n")))
```