Pythonノートのリスト解析

4926 ワード

リスト解析りすとかいせき:関数プログラミングツールかんすうプログラミングつーる
リスト解析(リスト導出とも呼ばれる)は、リストを構築するショートカットです.リスト解析はmapやfilterなどの関数ツールに関連しており、ループに関連しているため、ここでいくつか言及します.
リスト解析とmap
まず小さな例を挙げて基礎知識を説明します.
#Python  ord          ASCII    (chr          )
>>>ord('s')
115

ここでは、文字列全体のすべての文字のASCII符号化を収集したいと仮定します.最初に考えた方法は、簡単なforループを書き、結果をリストに添付することかもしれません.
>>>res = []
>>>for x in 'spam':
...    res.append(ord(x))
...
>>>res
[115, 112, 97, 109]

しかし、mapは、コード内のリストの構造に関心を持つことなく、単一の関数呼び出しを使用することができ、簡単に実現できることを知っています.
>>>res = list(map(ord, 'spam'))
>>>res
[115, 112, 97, 109]

それでも、リスト解析式によって同じ結果を得ることができます.mapは1つの関数を1つのシーケンスにマッピングし、リスト解析は1つの式を1つのシーケンスにマッピングします.
>>>res = [ord(x) for x in 'spam']
>>>res
[115, 112, 97, 109]

リスト解析は、シーケンスの値に任意の式を適用し、その結果を新しいシーケンスに収集して返します.文法的には,リスト解析は四角カッコでカプセル化されている.
前の例の効果は、forループとmap呼び出しを手動で行うのと比較して、何の違いもありません.しかし、リスト解析は、1つのシーケンスに任意の式を適用したい場合に便利になります.
>>>[x ** 2 for x in range(10)]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

ここでは0~9の数字の平方を集めました.map呼び出しとあまり差がなく、匿名関数を作成して平方操作を実現することもできます.
>>>list(map((lambda x: x ** 2), range(10)))
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

テストとネストループの追加
リスト解析は、現在説明しているよりも一般的です.forサイクルの後にif分岐を記述し,選択論理を増大させることができる.ifブランチを使用したリスト解析は、ブランチが本物ではない場合にシーケンスをスキップする内蔵filterのようなツールとして使用できます.
ここでは0~4偶数から選択した例を挙げる.また、比較のために、filterバージョンを書いてlambda関数を作成しました.
>>>[x for x in range(5) if x % 2 == 0]
[0, 2, 4]


>>>list(filter((lambda x: x % 2 == 0), range(5)))
[0, 2, 4]


>>>res = []
   for x in range(5):
       if x % 2 == 0:
           res.append(x)    
>>>res  
[0, 2, 4] 

これらはすべて余剰演算子%を使用して、その数が偶数でないかどうかを検出します.filter呼び出しもここのリスト解析に比べて短い.それでも、リスト解析ではifブランチと任意の式を混合することができ、単一の式を通じてfilterとmapと同じ効果を与えることができます.
今回は0~9の偶数の平方を集めてみましょう.右のifで偽物が得られると、forループはこれらの数字をスキップし、左の式で値を計算します.この等価なmapは、このステップを完了するためにより多くの作業を呼び出す.map反復でfilter選択プロセスを混合する必要があります.これにより、式は明らかに複雑になります.
>>>[x ** 2 for x in range(10) if x % 2 == 0]
[0, 4, 16, 36, 64]


list(map((lambda x: x**2), filter((lambda x: x % 2 == 0), range(10))))
[0, 4, 16, 36, 64]

実際には,リスト解析はさらに汎用的である.リスト解析で任意の数のネストされたforループを記述でき、それぞれにオプションの関連ifテストがあります.
最後に,ネストされたforが文からif選択を付加する役割を示す複雑な複数のリスト解析ツールがある.
>>>[(x, y) for x in range(5) if x % 2 == 0 for y in range(5) if y % 2 == 1]
[(0, 1), (0, 3), (2, 1), (2, 3), (4, 1), (4, 3)]

この式は0~4の偶数と0~4の奇数の組み合わせを並べている.if文は、各シーケンスで反復する必要がある要素をフィルタします.ここでは、文で記述された等価なコードです.
>>> for x in range(5):
...     if x % 2 == 0 :
...         for y in range(5):
...             if y % 2 == 1:
...                 res.append((x, y))
>>> res
[(0, 1), (0, 3), (2, 1), (2, 3), (4, 1), (4, 3)]

注意:複雑なリスト解析を理解するのが難しい場合は、リスト解析のforとif文をネスト(後の文を右にインデント)して、等価な文を得ることができます.
リストの解析と読み取り可能性
まず2段のコードをください.どの例のコードが読みやすいと思いますか.
>>>#  1
>>>symbols = '$¢ǥ£€¤'
>>>codes = []
>>>for symbol in symbols:
...    codes.append(ord(symbol))

>>>codes
[36, 162, 485, 163, 8364, 164]
>>>#  2
>>>symbols = '$¢ǥ£€¤'
>>>codes = [ord(symbol) for symbol in symbols]
>>>codes
[36, 162, 485, 163, 8364, 164]

Pythonを少し習ったことのある人なら誰でも例1は読めるはずですが、リスト解析をマスターすれば例2の方が読みやすいと思います.
リスト解析は、シーケンスまたは反復可能な他のタイプの要素をフィルタまたは加工し、リストを新規作成するのに役立ちます.Pythonに内蔵されたfilterとmap関数を組み合わせてもこの効果は得られますが、可読性には大きな割引があります.
リスト解析とfilterとmapの比較
filterとmapを合わせてできることは、リスト解析も可能であり、理解しにくいlambda(匿名関数)式を借りる必要はありません.例3を見る前にfilterとmapについて説明します.
filter()関数は、シーケンスをフィルタリングし、条件に合致しない要素をフィルタリングし、条件に合致する要素からなる新しいリストを返します.2つのパラメータが受信され、1つ目は関数、2つ目はシーケンスであり、シーケンスの各要素はパラメータとして関数に渡され、TrueまたはFalseに戻り、最後にTrueに戻った要素を新しいリストに配置します.
以下はfilter構文です
filter(function, iterable)
function --     。
iterable --      

map()は、指定した関数に基づいて指定したシーケンスをマッピングします.最初のパラメータfunctionは、パラメータシーケンスの各要素でfunction関数を呼び出し、各function関数の戻り値を含む新しいリストを返します.
以下はmap構文です
map(function, iterable, ...)
function --   
iterable --        

filterとmapについて説明した後、例3を見て、リスト導出とfilter/mapの組み合わせを使用して同じフォームを作成します.
>>>symbols = '$¢ǥ£€¤'
>>>beyond_ascii = [ord(s) for s in symbols if ord(s) > 127]
>>>beyond_ascii
[162, 485, 163, 8364, 164]
>>>beyond_ascii = list(filter(lambda c: c > 127, map(ord, symbols)))
>>>beyond_ascii
[162, 485, 163, 8364, 164]

個人的にはmap/filterの組み合わせはリスト解析よりも速いと思います(しかもmap/filterを使うと書くコードがすごいと思います).
 
Pythonリスト解析についてのまとめはここまでです.初めてCSDNでブログを書くのは間違いが避けられないので、間違いを指摘してください.Pythonerの学業が成功することを望んでいます.