はじめに
本記事は言語処理100本ノックの解説です。
100本のノックを全てこなした記録をQiitaに残します。
使用言語はPythonです。
今回は第2章:UNIXコマンド(10~19)までの解答例をご紹介します。
第2章: UNIXコマンド
popular-names.txtは,アメリカで生まれた赤ちゃんの「名前」「性別」「人数」「年」をタブ区切り形式で格納したファイルである.以下の処理を行うプログラムを作成し,popular-names.txtを入力ファイルとして実行せよ.さらに,同様の処理をUNIXコマンドでも実行し,プログラムの実行結果を確認せよ.
10. 行数のカウント
行数をカウントせよ.確認にはwcコマンドを用いよ.
Python
with open("[PATH]/popular-names.txt", "r") as f:
lines = f.readlines()
count = len(lines)
print(count)
2780
UNIXコマンド
$ wc -l "[PATH]/popular-names.txt"
2780
コメント
wc→word countですね。この章はPythonとコマンドのどちら掲載していきます。
11. タブをスペースに置換
タブ1文字につきスペース1文字に置換せよ.確認にはsedコマンド,trコマンド,もしくはexpandコマンドを用いよ.
Python
with open("[PATH]/popular-names.txt", "r") as f:
for line in f:
print(line.replace('\t', ' '))
Mary F 7065 1880
Anna F 2604 1880
Emma F 2003 1880
Elizabeth F 1939 1880
Minnie F 1746 1880
Margaret F 1578 1880
~~~~~~~~~~省略~~~~~~~~~~~
UNIXコマンド
$ cat '[PATH]/popular-names.txt' | sed 's/\t/ /'
$ cat '[PATH]/popular-names.txt' | tr '\t' ' '
$ cat '[PATH]/popular-names.txt' | expand
Mary F 7065 1880
Anna F 2604 1880
Emma F 2003 1880
Elizabeth F 1939 1880
Minnie F 1746 1880
Margaret F 1578 1880
~~~~~~~~~~省略~~~~~~~~~~~
コメント
UNIXコマンドは3つ作成。catは初見「なんで猫?」ってなりません?
12. 1列目をcol1.txtに,2列目をcol2.txtに保存
各行の1列目だけを抜き出したものをcol1.txtに,2列目だけを抜き出したものをcol2.txtとしてファイルに保存せよ.確認にはcutコマンドを用いよ.
Python
basepath = "[PATH]/"
with open("{}popular-names.txt".format(basepath), "r") as f, open("{}col1.txt".format(basepath), "w") as fc1, open("{}col2.txt".format(basepath), "w") as fc2:
lines = f.readlines()
count = len(lines)
for i, line in enumerate(lines):
name, sex, _, _ = line.split(' ')
if count == i:
fc1.write(name)
fc2.write(sex)
else:
fc1.write(name + '\n')
fc2.write(sex + '\n')
Mary
Anna
Emma
Elizabeth
Minnie
~~~~~~~~~~省略~~~~~~~~~~~
F
F
F
F
F
~~~~~~~~~~省略~~~~~~~~~~~
UNIXコマンド
#1列目
$ cut -f 1 -d " " '[PATH]/popular-names.txt'
#2列目
$ cut -f 2 -d " " '[PATH]/popular-names.txt'
#1列目
Mary
Anna
Emma
Elizabeth
Minnie
~~~~~~~~~~省略~~~~~~~~~~~
#2列目
F
F
F
F
F
~~~~~~~~~~省略~~~~~~~~~~~
コメント
テキスト出力するときに最終行だけ改行コード外す方法、ちょっと考えがち。
13. col1.txtとcol2.txtをマージ
12で作ったcol1.txtとcol2.txtを結合し,元のファイルの1列目と2列目をタブ区切りで並べたテキストファイルを作成せよ.確認にはpasteコマンドを用いよ.
Python
basepath = "[PATH]/"
with open("{}col1.txt".format(basepath), "r") as fc1, open("{}col2.txt".format(basepath), "r") as fc2, open("{}col1col2.txt".format(basepath), "w") as f:
i = 0
linesfc1 = fc1.readlines()
linesfc2 = fc2.readlines()
count = len(lines)
for name, sex in zip(linesfc1, linesfc2):
name = name.replace("\n", "")
sex = sex.replace("\n", "")
i += 1
if count == i:
f.write(name + "\t" + sex)
else:
f.write(name + "\t" + sex + "\n")
Mary F
Anna F
Emma F
Elizabeth F
Minnie F
~~~~~~~~~~省略~~~~~~~~~~~
UNIXコマンド
$ paste '[PATH]/col1.txt' '[PATH]/col2.txt'
Mary F
Anna F
Emma F
Elizabeth F
Minnie F
~~~~~~~~~~省略~~~~~~~~~~~
コメント
pasteコマンドはデフォルトでタブ区切りにしてくれるからオプション無しでオッケー。
14. 先頭からN行を出力
自然数Nをコマンドライン引数などの手段で受け取り,入力のうち先頭のN行だけを表示せよ.確認にはheadコマンドを用いよ.
Python
basepath = "[PATH]/"
with open("{}popular-names.txt".format(basepath), "r") as f:
val = int(input())
lines = f.readlines()
for i in range(val):
lines[i] = lines[i].replace('\n', '')
print(lines[i])
Mary F 7065 1880
Anna F 2604 1880
Emma F 2003 1880
Elizabeth F 1939 1880
Minnie F 1746 1880
UNIXコマンド
$ head -n 5 "[PATH]/popular-names.txt"
Mary F 7065 1880
Anna F 2604 1880
Emma F 2003 1880
Elizabeth F 1939 1880
Minnie F 1746 1880
コメント
Pythonのinput()ってあまり使わないですよね。
15. 末尾のN行を出力
自然数Nをコマンドライン引数などの手段で受け取り,入力のうち末尾のN行だけを表示せよ.確認にはtailコマンドを用いよ.
Python
basepath = "[PATH]/"
with open("{}popular-names.txt".format(basepath), "r") as f:
val = int(input())
lines = f.readlines()
count = len(lines) - 1
for i in reversed(range(val)):
result = lines[count - i].replace('\n', '')
print(result)
Benjamin M 13381 2018
Elijah M 12886 2018
Lucas M 12585 2018
Mason M 12435 2018
Logan M 12352 2018
UNIXコマンド
$ tail -n 5 "[PATH]/popular-names.txt"
Benjamin M 13381 2018
Elijah M 12886 2018
Lucas M 12585 2018
Mason M 12435 2018
Logan M 12352 2018
コメント
今度は後ろから取ってくる問題。リストの番号指定を工夫するところ。
16. ファイルをN分割する
自然数Nをコマンドライン引数などの手段で受け取り,入力のファイルを行単位でN分割せよ.同様の処理をsplitコマンドで実現せよ.
Python
import numpy as np
basepath = "[PATH]/"
with open("{}popular-names.txt".format(basepath), "r") as f:
val = int(input())
lines = f.readlines()
count = len(lines)
num_list = range(count)
div_list = np.array_split(num_list, val)
for i, div in enumerate(div_list, 1):
f = open('{}{}.txt'.format(basepath, str(i).zfill(3)), 'w')
for j in div:
f.write(lines[j])
f.close()
# 001.txt
Mary F 7065 1880
Anna F 2604 1880
Emma F 2003 1880
~~~省略~~~
# 002.txt
Virginia F 16162 1926
Mildred F 13551 1926
Frances F 13355 1926
~~~省略~~~
# 003.txt
John M 43181 1972
Robert M 43037 1972
Jason M 37446 1972
UNIXコマンド
$ split -n 3 -d --additional-suffix=.txt "[PATH]/popular-names.txt" "[出力先のPATH]"
# 00.txt
Mary F 7065 1880
Anna F 2604 1880
Emma F 2003 1880
~~~省略~~~
# 01.txt
Donald M 23840 1927
Joseph M 23506 1927
Edward M 19113 1927
~~~省略~~~
# 02.txt
Matthew M 24546 1973
Jennifer F 63114 1974
Amy F 29565 1974
~~~省略~~~
コメント
分割したファイルの名前は結局何が良いのか。。
17. 1列目の文字列の異なり
1列目の文字列の種類(異なる文字列の集合)を求めよ.確認にはcut, sort, uniqコマンドを用いよ.
Python
basepath = "[PATH]/"
with open("{}popular-names.txt".format(basepath), "r") as f:
lines = f.readlines()
name = sorted(set(map(lambda x: x.split(' ')[0], lines)))
print(name)
['Abigail', 'Aiden', 'Alexander', 'Alexis', 'Alice', ~~省略
UNIXコマンド
$ cut -d ' ' -f 1 "[PATH]/popular-names.txt"|sort|uniq
Abigail
Aiden
Alexander
Alexis
Alice
~~~省略~~~
コメント
めっちゃ入れ子構造になった。ここにきてlambdaが初登場。lambda関数を理解できたらPython中級者ですかね?
18. 各行を3コラム目の数値の降順にソート
各行を3コラム目の数値の逆順で整列せよ(注意: 各行の内容は変更せずに並び替えよ).確認にはsortコマンドを用いよ(この問題はコマンドで実行した時の結果と合わなくてもよい).
Python
basepath = "[PATH]/"
with open("{}popular-names.txt".format(basepath), "r") as f:
lines = f.readlines()
lines = map(lambda x: x.replace("\n",""), lines)
temp = list(map(lambda x: x.split(' '), lines))
pnum = sorted(temp, key=lambda x: int(x[2]), reverse=True)
print(pnum)
[['Linda', 'F', '99689', '1947'], ['Linda', 'F', '96211', '1948'], ['James', 'M', '94757', '1947'], ~~省略
UNIXコマンド
$ sort -n -r -k 3,3 -t " " "[PATH]/popular-names.txt"
Linda F 99689 1947
Linda F 96211 1948
James M 94757 1947
~~~省略~~~
コメント
UNIXコマンドのsortにたくさんオプションがついてる。
19. 各行の1コラム目の文字列の出現頻度を求め,出現頻度の高い順に並べる
各行の1列目の文字列の出現頻度を求め,その高い順に並べて表示せよ.確認にはcut, uniq, sortコマンドを用いよ
Python
import collections
basepath = "[PATH]/"
with open("{}popular-names.txt".format(basepath), "r") as f:
lines = f.readlines()
temp = list(map(lambda x: x.split(' '), lines))
c = collections.Counter(map(lambda x: x[0], temp))
c2 = c.most_common()
print(c2)
[('James', 118), ('William', 111), ('John', 108), ('Robert', 108), ('Mary', 92),~~省略
UNIXコマンド
$ cut -d ' ' -f 1 "[PATH]/popular-names.txt"|sort|uniq -c|sort -r -n
118 James
111 William
108 Robert
108 John
92 Mary
~~~省略~~~
コメント
collectionsモジュールを使用。Pythonは便利なモジュールが揃っていていいですよね~~
他章の解答例