内包表記とは
pythonでリストや辞書を作るときに使える記法。pythonはforループが遅いので、リストや辞書を作るときは内包表記を使うと段違いに高速化することができる。
基本
リストを作る場合はこんな感じ。
new_list = [f(myiter) for myiter in origin_list]
[ ]を{ }に替えると辞書も作れる。
new_dict = {indexes[myiter]:f(myiter) \
for myiter in origin_list}
基本的なパターンは下記になる。
[(iteraterを使った表現) for (iterater) in (元となるiterableオブジェクト)]
ifで条件分岐を使う
ifだけ場合
ifを1つだけ使う場合は最後につける。
odd = [i for i in range(10) if i%2 != 0]
# [1,3,5,7,9]
このときifはフィルタとしてはたらく。
if elseを使う場合
elseも使う場合はforの前につける。
xx = ["even" if i%2==0 else "odd" for i in range(10)]
# ['even', 'odd', 'even', 'odd', 'even', 'odd', 'even', 'odd', 'even', 'odd']
なぜifを前につけないといけないかというと、この時のifはさっきのifとは異なり、三項演算子の一部だからである。"even" if i%2 == 0 else "odd"
で一つの表現になっていて、それがforで繰り返されることになる。
なおelseは複数使えない。複数の条件分岐をする場合、elifは使えない。if elseを複数使えば実現できる。
添え字が複数ある場合
一列に並べるパターン
xx = [i+j for i in i_list for j in j_list]
ネストするパターン
xx = [[i+j for i in range(3)] for j in range(5)]
numpyの操作を使いたかったらnp.arrayに渡す。
xx = np.array([[i+j for i in range(3)] for j in range(5)])
numpy.arrayはなかなか賢いので、2重、3重、4重でもちゃんと成型してくれる。
zipを使うパターン
(0,0),(1,1),(2,2),...と並べる。
xx = [i+j for i,j in zip(mylist_i,mylist_j)]
沼に突っ込まないために
ここまで来て、すでに「うっ」となるかもしれない。リスト内包表記は改行にルールがないので、1行が長くなり難読化してしまう。なので長くなる場合は必ず適切に改行を入れる。
VSCodeの場合は1行目に\をいれれば、以降はいい感じに整形してくれる。実際は\を入れても入れなくても走る。
# ifを使う場合は絶対改行する
xx = ["even" if i % 2 == 0 else "odd" \
for i in range(10)]
# 表現が長くなるなら、長くなる所で改行を入れる
zz = [np.sin(xx) + np.random.rand(xx.shape) \
for xx in list_xx]