北野坂備忘録

主にインストールやプログラミングのメモを載せています。

言語処理100本ノック 2015年版 (10~19)

 とりあえず今回から問題も表記していく。

10. 行数のカウント

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

#!/usr/bin/env python

import codecs

fin  = codecs.open('hightemp.txt', 'r', 'utf_8')

if __name__ == "__main__":
  x = 0
  for line in fin:
    x += 1
  print(x)

この章のベースとなる読み込みの処理を書くだけ。codecsモジュールを使用。

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

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

#!/usr/bin/env python

import codecs
import re

fin  = codecs.open('hightemp.txt', 'r', 'utf_8')

if __name__ == "__main__":
  x = 0
  for line in fin:
    dst = re.sub('\t', ' ', line)
    print(dst,end="")

正規表現操作モジュールreを使用。

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

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

#!/usr/bin/env python

import codecs

fin  = codecs.open('hightemp.txt', 'r', 'utf_8')

col1=[]
col2=[]

if __name__ == "__main__":
  for line in fin:
    l = line.split("\t")
    col1.append(l[0])
    col2.append(l[1])
  else:
    print('\n'.join(col1))
    print("")
    print('\n'.join(col2))
    with codecs.open('col1.txt', 'w', 'utf_8') as file1:
      file1.write('\n'.join(col1))
    with codecs.open('col2.txt', 'w', 'utf_8') as file2:
      file2.write('\n'.join(col2))
    fin.close()

splitとリストのスライスと書き込み処理を使用させる問題。

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

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

#!/usr/bin/env python

import codecs

fin1  = codecs.open('col1.txt', 'r', 'utf_8')
fin2  = codecs.open('col2.txt', 'r', 'utf_8')

line=[]

if __name__ == "__main__":
  for line1,line2 in zip(fin1,fin2):
    line1 = line1.rstrip()
    line.append(line1+"\t"+line2)
  else:
    print(''.join(line))
    with codecs.open('col12.txt', 'w', 'utf_8') as file:
      file.write(''.join(line))
  fin1.close()
  fin2.close()  

zip関数を使わせる問題かなー。col1データの末尾がヤな感じになるのでrstrip()を使用。

14. 先頭からN行を出力

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

#!/usr/bin/env python

import codecs
import sys 
 
fin  = codecs.open('hightemp.txt', 'r', 'utf_8')
argvs = sys.argv
argc = len(argvs)
if (argc != 2):
    print("Usage: # python %s number" % argvs[0])
    quit() 

if __name__ == "__main__":
  x = 0
  for line in fin:
    if x < int(argvs[1]):
      print(line,end="")
    else:
      break
    x += 1

コマンドライン引数を処理させる問題。sysモジュールを使用。

15. 末尾のN行を出力

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

#!/usr/bin/env python

import codecs
import sys 
 
fin  = codecs.open('hightemp.txt', 'r', 'utf_8')
argvs = sys.argv
argc = len(argvs)
if (argc != 2):
    print("Usage: # python %s number" % argvs[0])
    quit() 

if __name__ == "__main__":
  x = 0
  for line in fin:
    x += 1
  fin  = codecs.open('hightemp.txt', 'r', 'utf_8')
  y = 0
  for line in fin:
    if y > x - int(argvs[1]) - 1:
      print(line,end="")
    y += 1

 10で作った行数をカウントするコードを再利用。空回しして行数だけ先に入手して計算。2回for文を使っているので遅くなる?1回で済ますために全行を取り込むのは行数が増えると遅くなるような気がするな。

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

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

#!/usr/bin/env python

import codecs
import sys 
 
fin  = codecs.open('hightemp.txt', 'r', 'utf_8')
argvs = sys.argv
argc = len(argvs)
if (argc != 2):
    print("Usage: # python %s number" % argvs[0])
    quit()

line1 = []

if __name__ == "__main__":
  x = 0
  vol = int(argvs[1])
  for line in fin:
    x += 1
  linenum = round(x / vol)
  fin  = codecs.open('hightemp.txt', 'r', 'utf_8')
  i = 0
  y = 0
  for line in fin:
    if y < linenum:
      line1.append(line)
      y += 1
    else:
      filename = "out{0}.txt".format(i)
      print(filename)
      with codecs.open(filename, 'w', 'utf_8') as file:
        file.write(''.join(line1))
      y  = 1
      line1 =[]
      line1.append(line)
      i += 1
  filename = "out{0}.txt".format(i)
  print(filename)
  with codecs.open(filename, 'w', 'utf_8') as file:
      file.write(''.join(line1))

splitコマンドはN分割するコマンドではなくN行で分割していくコマンド。問題文を何回か見直すがやはりNで分割だな。24行なので、5分割すると{5,5,5,5,4}行で分割されるようにしたい。変数を使った動的なファイル名付けも課題か。

17. 1列目の文字列の異なり

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

#!/usr/bin/env python

import codecs
 
fin  = codecs.open('hightemp.txt', 'r', 'utf_8')

col1 = []

if __name__ == "__main__":

  for line in fin:
    l = line.split("\t")
    col1.append(l[0])
  else:
    print(col1)
    X = set(col1)
    print(X)
    print(len(X), end='')
    print("種類")

 これ実は問12と問06の答えを組み合わせれば一瞬で終わる。だが、これまでの問題列の傾向を考えるとsort部とuniq部に分けて実装したほうがあとあと良いような気がする。

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

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

#!/usr/bin/env python

import codecs
 
fin  = codecs.open('hightemp.txt', 'r', 'utf_8')

col1 = []
col2 = []
line1 = []

if __name__ == "__main__":

  for line in fin:
    l = line.split("\t")
    col1.append(l)
  col2 = sorted(col1,key=lambda x: x[2], reverse=True)
  for line in col2:
    line1 = ' '.join(line)
    print(line1,end="")

 あーやっぱり問17でsort実装しておけばよかった。とはいえそれほど難しい問題でもない。今回はkey付きsortedを使用。

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

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

#!/usr/bin/env python

import codecs
from collections import Counter
 
fin  = codecs.open('hightemp.txt', 'r', 'utf_8')

col1 = []

if __name__ == "__main__":

  for line in fin:
    l = line.split("\t")
    col1.append(l[0])
  counter = Counter(col1)
  for word, cnt in counter.most_common():
    print(word, cnt)

 出現頻度を計算するアルゴリズムをスクラッチで作るべきか悩んだが、Counterの存在を知っていたためそちらを使う。

 この問題集ではこういうアルゴリズムをスクラッチで書いていくことを期待しているのか、それとも適切なモジュールを知っている/見つけてくることを期待しているのか、どちらでもいいのか。
 今までの傾向からすると適切なモジュールを適切に使うほうかな。