こんにちは。福田直起です。
前回に引き続き、言語処理100本ノック2020を解いているアウトプットとして、「第2章 : UNIXコマンド」の10問のうち、Q12とQ13の2問を解説していきます。
他の問題の回答は、まとめページにリンクを貼ってあります。
解答・解説の前に
この記事の
- 主な対象者と目的
- 実行環境
- 解答・解説を読む際の注意
は、以前の記事で説明していますので、解答・解説を読む前にこれらを知っておきたい、という方はそちらを参照していただくようお願いします。
また、長い解説は折りたたんであります。折りたたんである解説は「解説を読む」をクリックすると見ることができます。
解答・解説
Q12. 1列目をcol1.txtに,2列目をcol2.txtに保存
各行の1列目だけを抜き出したものをcol1.txtに,2列目だけを抜き出したものをcol2.txtとしてファイルに保存せよ.確認にはcutコマンドを用いよ.
Python
解答コード
(別解があるため、指定されたファイル名のあとに連番をつけています)
# 以降の解答でも使用 PATH_COL1_1 = "data/col1-1.txt" PATH_COL2_1 = "data/col2-1.txt" with open("popular-names.txt") as input_file: lines = input_file.readlines() with open(PATH_COL1_1, mode="w") as col1, open(PATH_COL2_1, mode="w") as col2: for line in lines: split = line.split() col1.write(split[0] + "\n") col2.write(split[1] + "\n") print("ファイルの書き出しが完了しました")
実行結果
ファイルの書き出しが完了しました
解説
解説を読む
Pythonで複数のファイルを同時に開く方法
with open(ファイルまでのパス) as 変数名, open(ファイルまでのパス) as 変数名:
のようにすることで、一行で複数のファイルを同時に開くことができ、ネストが深くなるのを防ぐことができます。
使用例:
with open(PATH_COL1_1, mode="w") as col1, open(PATH_COL2_1, mode="w") as col2: for line in lines: split = line.split() col1.write(split[0] + "\n") col2.write(split[1] + "\n")
また、以下にこの問題をtry finally
を使って解いた別解も載せておきます。
PATH_COL1_2 = "data/col1-2.txt" PATH_COL2_2 = "data/col2-2.txt" input_file = None col1 = None col2 = None # try finallyを使う例 try: input_file = open("popular-names.txt") col1 = open(PATH_COL1_2, mode="w") col2 = open(PATH_COL2_2, mode="w") for line in input_file: split = line.split() col1.write(split[0] + "\n") col2.write(split[1] + "\n") finally: if input_file is not None: input_file.close() input_file = None if col1 is not None: col1.close() col1 = None if col2 is not None: col2.close() col2 = None print("ファイルの書き出しが完了しました")
with
だとネストが深くなるか、一行が長くなるかのどちらかの問題を抱えることになってしまうので、今回のように複数のファイルを同時に開きたい場合は、try finally
を使うほうがわかりやすいかもしれません。
このtry finally
でファイルを開く方法は、以前の記事で詳しく解説しています。
UNIXコマンド
解答コード
!echo "Pythonの出力ファイルとUNIXコマンドで同様の処理をした結果を比較:" !echo "diff <(cut -f 1 popular-names.txt)" $PATH_COL1_1 !diff <(cut -f 1 popular-names.txt) $PATH_COL1_1 !echo !echo "diff <(cut -f 2 popular-names.txt)" $PATH_COL2_1 !diff <(cut -f 2 popular-names.txt) $PATH_COL2_1
実行結果
Pythonの出力ファイルとUNIXコマンドで同様の処理をした結果を比較: diff <(cut -f 1 popular-names.txt) data/col1-1.txt diff <(cut -f 2 popular-names.txt) data/col2-1.txt
解説
解説を読む
UNIXのcut
コマンドについて
cut -f 列番号 対象ファイル
のように指定することで、タブ区切りのファイルから指定した列を切り出すことができるコマンドです。
Pythonなどのプログラミング言語に慣れている方は、列番号で一列目を指定したいなら0、二列目なら1……のように指定するものだと思うかもしれませんが、cut
コマンドでは一列目なら1、二列目なら2を指定する必要があることに注意しましょう。のちの問題で使うsort
コマンドなど、他のUNIXコマンドも同じような仕様のものがあります。
使用例:
cut -f 2 popular-names.txt
参考: 【 cut 】コマンド――行から固定長またはフィールド単位で切り出す:Linux基本コマンドTips(60) - @IT
Q13. col1.txtとcol2.txtをマージ
12で作ったcol1.txtとcol2.txtを結合し,元のファイルの1列目と2列目をタブ区切りで並べたテキストファイルを作成せよ.確認にはpasteコマンドを用いよ.
Python
解答コード
# 以降の解答でも使用 PATH_Q13 = "data/q13.txt" # Q12で定義した定数を使用 with open(PATH_COL1_1) as col1: lines_col1 = col1.readlines() with open(PATH_COL2_1) as col2: lines_col2 = col2.readlines() with open(PATH_Q13, mode="w") as q13: for line1, line2 in zip(lines_col1, lines_col2): # 1列目のファイルの改行をタブ文字に置換することで、タブ区切りとしている q13.write(line1.replace("\n", "\t") + line2) print("ファイルの書き出しが完了しました")
実行結果
ファイルの書き出しが完了しました
解説
コード中にもコメントしていますが、1列目のファイルの改行をタブ文字に置換することで、タブ区切りで並べたテキストファイルを出力するという工夫をしています。
UNIXコマンド
解答コード
!echo "Pythonの出力ファイルとUNIXコマンドで同様の処理をした結果を比較:" !echo "diff <(paste" $PATH_COL1_1 $PATH_COL2_1")" $PATH_Q13_1 !diff <(paste $PATH_COL1_1 $PATH_COL2_1) $PATH_Q13_1
実行結果
Pythonの出力ファイルとUNIXコマンドで同様の処理をした結果を比較: diff <(paste data/col1-1.txt data/col2-1.txt) data/q13-1.txt
解説
解説を読む
UNIXのpaste
コマンドについて
paste 結合したいファイル1 結合したいファイル2
のようにすることで、ファイル2つを行単位で結合した結果を出力することができるコマンドです。
使用例:
paste fileA.csv fileB.csv
行数の異なるファイルを結合した場合、以下のように一方だけにある行は片方だけのまま出力されます。
# 2行あるファイルと1行しかないファイルをpasteした例 paste paste_test.csv paste_test2.csv John M 50000 2000 John M 50000 2000 John M 50000 2000
参考: 【 paste 】コマンド――複数のファイルを行単位で連結する:Linux基本コマンドTips(101) - @IT
おわりに
以上、言語処理100本ノックの第2章のQ12とQ13について解説しました。
今回紹介したcut
とpaste
は、データが保存されたテキストファイルを扱う際に覚えておくと役に立つと思います。
他の問題の回答は、まとめページにリンクを貼ってあります。
また、ブレインズコンサルティングでは一緒に働いてくれる仲間を募集しています。 ご興味のある方は、ぜひ一度採用サイトをご覧ください。