Table of Contents
はじめに
リスト操作は毎回同じことを調べ直しがちな領域です。この記事では、実際に使う頻度の高いものをまとめました。書き方が複数あるものは、どれを選ぶべきかまで書いています。
リストを文字列に変換する
join() を使います。呼び出すのは「区切り文字のほう」である点に注意してください。
lst = ["a", "b", "c"]
",".join(lst)# 'a,b,c'
"\n".join(lst)# a# b# cリストにリストをつなげる
extend() を使うのがもっとも素直です。
lst = ["I", "my", "me"]addlist = ["one", "two", "three"]
lst.extend(addlist)# ['I', 'my', 'me', 'one', 'two', 'three']+= でも同じ結果になります。
lst += addlist新しいリストを作りたい場合は + を使います。
new_lst = lst + addlist # 元のlstは変わらない入れ子になったリストを平坦にする
書き方は2つあります。どちらも結果は同じです。
nested = [[0, 1], [2, 3], [4, 5, 6]]
# 1. リスト内包表記[i for lst in nested for i in lst]# [0, 1, 2, 3, 4, 5, 6]
# 2. itertools を使うimport itertools
list(itertools.chain.from_iterable(nested))# [0, 1, 2, 3, 4, 5, 6]内包表記は追加のimportが要らず、itertools のほうは要素数が多いときにわずかに速くなります。普段は内包表記で十分です。
内包表記の for の順序は、外側のループから先に書きます。通常のfor文を左から右へ並べたものと同じ順です。
# これと同じ意味result = []for lst in nested: for i in lst: result.append(i)重複を除いて順序を保つ
set() は重複を消しますが、順序が保証されません。順序を保ったまま重複を除くなら dict.fromkeys() を使います。
lst = ["john", "alice", "joe", "john"]
list(dict.fromkeys(lst))# ['john', 'alice', 'joe']Python 3.7以降、辞書はキーの挿入順を保持することが言語仕様で保証されているため、この書き方が確実です。
空の要素を削除する
リスト内包表記で条件を指定します。
lst = ["", "a", "b", "", "", "c", ""]
[x for x in lst if x != ""]# ['a', 'b', 'c']if x と書くと、空文字だけでなく None や 0、空リストなど偽と評価されるすべてが除かれます。
lst = ["", "a", None, "b", 0, "c"]
[x for x in lst if x != ""] # ['a', None, 'b', 0, 'c'][x for x in lst if x] # ['a', 'b', 'c']金額の 0 を残したい場合に if x を使うと消えてしまうので、何を落としたいのかを意識して選んでください。
リストを任意のサイズに分割する
n個ずつのまとまりに切り分けます。
l = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]n = 3
[l[idx:idx + n] for idx in range(0, len(l), n)]# [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]range(0, len(l), n) で開始位置を n 個飛ばしに作り、そこから n 個ずつスライスする、という仕組みです。最後の余りは自動的に短いまとまりになります。
API へのリクエストを一定件数ずつに区切って送るときなどに使えます。
if を混ぜたリスト内包表記
条件に合う要素だけを集めます。
columns = ["I am Sam", "She is Erica", "He is Eric"]
[c for c in columns if "Sam" in c]# ['I am Sam']通常のfor文で書くとこうなります。
lst = []for c in columns: if "Sam" in c: lst.append(c)条件によって値を変えたい場合は、if を for の前に置く三項演算子の形になります。位置が違うので注意してください。
# 絞り込み: if は後ろ[c for c in columns if "Sam" in c]
# 値の変換: if〜else は前["該当" if "Sam" in c else "対象外" for c in columns]# ['該当', '対象外', '対象外']スライスのカンマ(numpy)
Pythonの標準リストは1次元のスライスしかできませんが、numpyの配列はカンマ区切りで次元ごとに指定できます。
import numpy as np
a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
a[:, 0] # [1 4 7] ← 全行の0番目a[:1, 0] # [1] ← 0行目までの0番目a[:2, 1] # [2 5] ← 0〜1行目の1番目a[:3, 1] # [2 5 8]カンマの前が行、後ろが列です。: だけを書くと「その次元すべて」を意味します。
おわりに
リスト操作は書き方が複数あるものが多く、どれも動いてしまうため、なんとなく最初に見つけた書き方を使い続けがちです。件数が増えたときに効いてくるのは重複除去のような処理なので、そこだけは書き方を選んでおくと後で困りません。
