はじめに
こちらの記事を拝見し、紹介されている Python のコードの別解を考えてみます。
- 動作確認環境
- Python 3.6.7, 3.7.5
やっていること
背景はここでは割愛しますが、docker イメージ名がリスト化された2つのファイル
checklist.txt
imagelist.txt
があり、checklist.txt
にあって、imagelist.txt
にないイメージ名を画面に表示するものです。
たとえば、2つのファイルがそれぞれ
checklist.txt
image1 image2 image3 image4 image5
imagelist.txt
image1 image3 image5
という状態であれば、
image2 image4
と出力します。
元のコード
#checkimage.py checklist = open("checklist.txt","r") imagelist = open("imagelist.txt", "r") checklists = [] imagelists = [] for line1 in checklist: checklists.append(line1) for line2 in imagelist: imagelists.append(line2) for check in checklists: if check not in imagelists: print(check.rstrip('\n')) checklist.close() imagelist.close()
わざわざ配列に入れる必要はないのかもしれませんが、そこは知識と時間不足でした、、 もしもっとスマートな書き方を知っている方は教えてください🙇♀️
とのことですので、私なりに4パターンほど考えたり、調べたりしました。
■ パターン1: ファイル読み込みを with
で囲う
ファイルを暗黙的、かつ確実に close
させるために open
を with
で囲うパターンです。
他は、元のコードと同じです。
checklists = [] imagelists = [] with open("checklist.txt", "r") as f: for line1 in f: checklists.append(line1) with open("imagelist.txt", "r") as f: for line2 in f: imagelists.append(line2) for check in checklists: if check not in imagelists: print(check.rstrip('\n'))
■ パターン2: リスト化に splitlines()
を利用する
パターン1をベースにして、ファイル内容のリスト化に splitlines()
を利用するパターンです。
受け取るリストの初期化と append
が不要になります。また、改行区切りで split されるので、表示時の .rstrip('\n')
も不要になるはず。
with open("checklist.txt", "r") as f: checklists = f.read().splitlines() with open("imagelist.txt", "r") as f: imagelists = f.read().splitlines() for check in checklists: if check not in imagelists: print(check)
■ パターン3: 差分を -
で求める
パターン2をベースにして、差分を -
で求めるパターンです。
比較する際のループが不要になります。ただし、セットに変換するので順番は維持されません。
with open("checklist.txt", "r") as f: checklists = f.read().splitlines() with open("imagelist.txt", "r") as f: imagelists = f.read().splitlines() diff = list(set(checklists) - set(imagelists)) for check in diff: print(check)
■ パターン4: 差分を filter
で求める
パターン3でベースにして、順番を維持するやり方がないかと調べたところを以下のページが参考になりました。
lcjvEm - Online Python3 Interpreter & Debugging Tool - Ideone.com
(コメントに「重複も保持される」とありますが「順番も」のことだと思います)
差分を filter
で求めるパターンです。
with open("checklist.txt", "r") as f: checklists = f.read().splitlines() with open("imagelist.txt", "r") as f: imagelists = f.read().splitlines() diff = list(filter(lambda x: x not in imagelists, checklists)) for check in diff: print(check)
おわりに
表示の仕方を含めるともっといろいろな方法があると思います。