Entry Title

言語処理100本ノック(15〜19)

15.末尾のN行を出力

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

解答(Python):

import sys

args = sys.argv

basefile = open('hightemp.txt')
basefile_line = basefile.readlines()
basefile_line_len = len(basefile_line)
displayline = basefile_line_len - int(args[1]) + 1

for x, y in reversed(list(enumerate(basefile_line, start=1))):
print(y)
if x == displayline:
break


basefile.close()

##########結果##########

(コマンドラインで3を入力した場合)

愛知県 名古屋 39.9 1942-08-02
山形県 鶴岡 39.9 1978-08-03
山梨県 大月 39.9 1990-07-19

解答(Unixコマンド):

$ tail -n 3 hightemp.txt

##########結果##########

山梨県 大月 39.9 1990-07-19
山形県 鶴岡 39.9 1978-08-03
愛知県 名古屋 39.9 1942-08-02

考察:Pythonではreversedしていますので、逆順です。なので、Unixコマンドの結果とは逆になっています。あんまり綺麗ではない...スライスで切り出して表示とかの方がいいのでしょうが、ひとまずこれで完了とします。

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

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

解答(Python):

import sys
import itertools

args = sys.argv

basefile = open('hightemp.txt')
basefile_line = basefile.readlines()

split_after = [x for x in itertools.zip_longest(*[iter(basefile_line)]*int(args[1]))]

for x, y in enumerate(split_after, start=0):
flopen = open('split_{0}.txt'.format(x + 1), 'w')
for z in split_after[x]:
if z is not None:
flopen.write(z)
flopen.close()

basefile.close()

##########結果##########

(コマンドラインで7を入力した場合)

◯split_1.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

◯split_2.txt
山梨県 勝沼 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

(以下、split_4.txtまで繰り返しのため省略)

解答(Unixコマンド):

$ split -l 7 hightemp.txt split_

##########結果##########

split_aa〜split_adでファイル出力。内容はPython版と変わらず。

考察:コマンド引数ごとに分割する方法を最初はzipでやっていたのですが、余剰がある場合は切り捨てられるという自体に陥ってどうしようと思っていたら、丁度良い記事が見つかりました。
(参考:http://iogi.hatenablog.com/entry/split-list-into-sublist:title
Unixコマンドでは「-d」オプションで出力するファイル名をPython版で統一しようと思ったら「split: -d: illegal line count」と言われました。何でだ...と調べたら、OS X版のsplitには存在しないということでした。(参考:https://apple.stackexchange.com/questions/138785/d-option-for-split-is-illegal-on-os-x-10-9

17.1列目の文字列の異なり

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

解答(Python):

basefile = open('col1.txt')
line = basefile.readlines()

commonlist = {x.replace('\n', '') for x in line}

basefile.close()

for y in commonlist:
print(y)

##########結果##########

岐阜県
埼玉県
千葉県
愛知県
愛媛県
大阪府
高知県
静岡県
和歌山県
群馬県
山梨県
山形県

解答(Unixコマンド):

$ cat col1.txt | sort | uniq

##########結果##########

Python版と同じ

考察:なし

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

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

解答(Python):

opfile = open('hightemp.txt')
fileline = opfile.readlines()
baselist = [[b for b in a.split('\t')] for a in fileline]
sortbasefile = sorted(baselist, key=lambda col3: col3[2], reverse=True)

newfile = open('col3sort.txt', 'w')
for x in sortbasefile:
newfile.write('\t'.join(x))

opfile.close()

##########結果##########

(col3sort.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

解答(Unixコマンド):

$ sort -r -k 3 hightemp.txt

##########結果##########

Python版と同じ

考察:sorted関数を利用するために、1行ずつリスト化し、3カラム目でソートしたものを新たなファイルに書き出す方針でやりました。やっている途中で気がついたのですが、対象ファイルが最初から降順でソートされている...ので結果は変わっていません。もし昇順するのであれば、sorted内のreverse=TrueをはずすだけでOKです。

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

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

解答(Python):

import pprint

opfile = open('hightemp.txt')
fileline = opfile.readlines()
sortcol = [x.split('\t')[0] for x in fileline]
count = {}

for a in sortcol:
count.setdefault(a, 0)
count[a] += 1

opfile.close()

count = sorted(count.items(), key=lambda x: x[1], reverse=True)

pprint.pprint(count)

##########結果##########

[('埼玉県', 3),
('山形県', 3),
('山梨県', 3),
('群馬県', 3),
('岐阜県', 2),
('静岡県', 2),
('愛知県', 2),
('千葉県', 2),
('高知県', 1),
('和歌山県', 1),
('愛媛県', 1),
('大阪府', 1)]

解答(Unixコマンド):

$ cut -f 1 hightemp.txt | sort | uniq -c | sort -n -r

##########結果##########

3 群馬県
3 山梨県
3 山形県
3 埼玉県
2 静岡県
2 愛知県
2 岐阜県
2 千葉県
1 和歌山県
1 高知県
1 愛媛県
1 大阪府

考察:Python版では、setdefaultの「存在したらスルー」を利用し、既に存在する場合はカウント+1をしています。Unixコマンドの方は、sortしてから再びsortするという方法じゃないと綺麗に出力されません...無知なだけだと思うので、しっかり勉強しなおしてから書き直したいと思います。

最近の投稿

0 コメント

現在コメントはありません

新しいコメント