#!/usr/bin/env python # coding: utf-8 # ## 通常のリスト生成 # (リスト外延表記: list extension) # In[1]: extension_1 = [] for i in range(10): extension_1.append(i) extension_1 # ## リスト内包表記 # list comprehension # 基本構文 # [ **element** for **element** in **iterator**] # 僕は先に`[i for i in]`だけ書いてから修飾することが多いです。 # In[2]: comprehension_1= [i for i in range(10)] comprehension_1 # ## 速度 # In[3]: get_ipython().run_cell_magic('timeit', '', 'extension_1 = []\nfor i in range(10000):\n extension_1.append(i)\n') # In[4]: get_ipython().run_cell_magic('timeit', '', 'comprehension_1= [i for i in range(10000)]\n') # list内包表記はコードがすっきりするだけでなく速度面でも有利です # [参考: Pythonの内包表記はなぜ速い?](http://dsas.blog.klab.org/archives/51742727.html) # 遅い理由は大きく2つ # - ループする度にリストオブジェクトのappendを参照する # - appendをpythonの関数として実行する # # 前者の影響はループの外に参照を追い出すことでも解消できます # In[5]: get_ipython().run_cell_magic('timeit', '', 'extension_1_ = []\nappend=extension_1_.append\nfor i in range(10000):\n append(i)\n') # ## ifを含む場合(後置if) # リスト内包表記は後置ifが使えます # In[6]: extension_2 =[] for i in range(10): if i%2==0: extension_2.append(i) extension_2 # In[7]: comprehension_2 = [i for i in range(10) if i%2==0] comprehension_2 # In[8]: get_ipython().run_cell_magic('timeit', '', 'extension_2 =[]\nfor i in range(10000):\n if i%2==0:\n extension_2.append(i)\n') # In[9]: get_ipython().run_cell_magic('timeit', '', 'comprehension_2 = [i for i in range(10000) if i%2==0]\n') # In[10]: get_ipython().run_cell_magic('timeit', '', 'extension_2_ =[]\nappend=extension_2_.append\nfor i in range(10000):\n if i%2==0:\n append(i)\n') # 実はifが計算律速になるので、無理にリスト内包表記にする必要がなかったりします。 # ## if ~ elseを含む場合 (条件演算子) # 紛らわしいですが、else節を含む場合は条件演算子(他で言う三項演算子)を使うのでifの位置が変わります # (条件演算子はpython 2.5以降のみ対応です) # In[11]: extension_3 =[] for i in range(10): if i%2==0: extension_3.append(i) else: extension_3.append(str(i)) extension_3 # In[12]: comprehension_3 = [ i if i%2==0 else str(i) for i in range(10)] comprehension_3 # 実際にはこちらと等価だと思えば理解しやすいかもしれません # In[13]: extension_3_conditional =[] for i in range(10): extension_3_conditional.append(i) if i%2==0 else extension_3_conditional.append(str(i)) extension_3_conditional # 一応速度を測ってみます # In[14]: get_ipython().run_cell_magic('timeit', '', 'extension_3 =[]\nfor i in range(10000):\n if i%2==0:\n extension_3.append(i)\n else:\n extension_3.append(str(i))\n') # In[15]: get_ipython().run_cell_magic('timeit', '', 'extension_3_ =[]\nappend=extension_3_.append\nfor i in range(10000):\n if i%2==0:\n append(i)\n else:\n append(str(i))\n') # In[16]: get_ipython().run_cell_magic('timeit', '', 'extension_3_conditional_ =[]\nappend=extension_3_conditional_.append\nfor i in range(10000):\n append(i) if i%2==0 else append(str(i))\n') # In[17]: get_ipython().run_cell_magic('timeit', '', 'comprehension_3 = [ i if i%2==0 else str(i) for i in range(10000)]\n') # あまり内包表記による高速化はありません # ## 辞書内包表記とセット内包表記 # python2.7以降ではリスト以外の内包表記として、辞書内包やセット内包も使えます。 # In[18]: comprehension_dict = {str(i):i for i in range(10)} print(comprehension_dict) # zipとかと相性いいです。 # In[19]: label = ["kinoko", "takenoko", "suginoko"] feature = ["yama", "sato", "mura"] {i:j for i,j in zip(label,feature)} # python2.6まではdictにtupleを渡してあげます。 # In[20]: comprehension_dict2 = dict((str(i),i) for i in range(10)) print(comprehension_dict2) # 後置ifも使えます。 # In[21]: comprehension_dict2 = {str(i):i for i in range(10) if i%2==0} print(comprehension_dict2) # 条件演算子も使えます。 # 条件演算子なので、「:」の前後のkeyとvalueそれぞれに記載する必要があります。 # In[22]: comprehension_dict3 = {str(i) if i%2==0 else i : i if i%2==0 else str(i) for i in range(10)} print(comprehension_dict3) # これは動かないです。(以前やりましたorz) # In[23]: comprehension_dict4 = {str(i):i if i%2==0 else i:str(i) for i in range(10)} # セット内包表記にしたい時は : なしで {} で囲みます。 # In[24]: comprehension_set={i%5 for i in range(10)} comprehension_set # ## ジェネレータ式とタプル内包表記 # 構文から勘違いしやすいですが、()で囲んでもタプル内包表記になりません。 # In[25]: comprehension_gen=(i%5 for i in range(10)) comprehension_gen # In[27]: for i in comprehension_gen:print(i) # ()で囲うとジェネレータが発生します。むしろタプル内包表記より使います。 # リストと違ってメモリ中に全要素を格納しないで、次の要素を順番に生成します。 # 内包表記を使わない書き方は下記ですが、一旦 ジェネレータを生成する関数を作らないと行けないので面倒です。 # In[28]: def gen_func(): for i in range(10): yield i extension_gen = gen_func() extension_gen # タプル内包表記が必要なことはあまりないですが、もしどうしても必要ならリスト内包表記をtuple関数に渡すしかないです。 # In[29]: tuple([i for i in range(10)]) # ## 闇への道 # この節を読み終えた後は[リーダブルコード](http://www.amazon.co.jp/dp/4873115655)を読んで浄化されることを推奨します。 # #### 条件演算子を複数つなげる # In[30]: for i in range(1,16): if i%15==0: print ("fizzbuzz") elif i%3==0: print ("fizz") elif i%5==0: print ("buzz") else: print(i) # In[31]: ["fizzbuzz" if i%15==0 else "fizz" if i%3==0 else "buzz" if i%5==0 else i for i in range(1,16)] # ネスト(多重配列) # In[32]: outer_list=[] for i in range(3): innter_list=[] for j in range(10): innter_list.append(j) outer_list.append(innter_list) outer_list # In[33]: [[j for j in range(10)] for i in range(3)] # フラッタン # この辺から可読性著しく悪くなります。 # In[34]: init=[[1,2,3],[4,5],[6,7]] # In[35]: flatten=[] for outer in init: for inner in outer: flatten.append(inner) flatten # これと等価 # In[36]: [inner for outer in init for inner in outer] # 基本的には左側のfor節から順番に読んでいって、最後にリストに入れるものが頭にくる # インデントするならこんな感じ # In[37]: [ inner for outer in init for inner in outer ] # パタトクカシー # In[38]: pato="パトカー" taxi="タクシー" rslt=[] for i in zip(pato,taxi): for j in i: rslt.append("".join(j)) "".join(rslt) # In[39]: "".join(["".join(j) for i in zip(pato,taxi) for j in i]) # インデントすると # In[40]: "".join( ["".join(j) for i in zip(pato,taxi) for j in i ] ) # printとか入れてもできる # In[41]: for i in zip(pato,taxi): for j in i: for k in j: print(k) # In[42]: [print(k) for i in zip(pato,taxi) for j in i for k in j] # if 節との多重ループの合わせ技 # In[43]: import re DIO=["U","無駄","RR","貧弱ゥ","Y"] # In[44]: rslt=[] for i in DIO: if re.match("[URY]+",i): for j in i: rslt.append(j*2) "".join(rslt) # In[45]: "".join([j*3 for i in DIO if re.match("[URY]+",i) for j in i]) # インデントするとこんな感じ # In[46]: "".join( [ j*4 for i in DIO if re.match("[URY]+",i) for j in i ] )