Python Language
リストの理解
サーチ…
前書き
[i ** 2 for i in range(1,11)]
既存のリストrange
のダミーi
を使用して新しい要素パターンを作成します。これは、より表現力の低い言語でforループが必要な場合に使用されます。
構文
- [私は範囲(10)で] i基本的なリストの理解
- [私はxrange(i)の中で]#基本的なリストの理解は、ジェネレータオブジェクトでPython 2.x
- [iが範囲(20)の場合はi%2 == 0]#フィルタ付き
- [3、4、5]のyの[1、2、3のxのxはy]]ネストされたループ
- [iが範囲6のiに対してi> 6 else 0]#三項式
- [iが4の場合はelse、iは範囲(20)の場合はi%2 == 0]#フィルタと三項式
- [3、4、5]]中のyに対する[[x、yの[1,2,3]中のxは、]#入れ子リストの理解
備考
リストの解説はPEP 202で概説され、Python 2.0で導入されました。
条件付きリストの理解
リストの理解度を考えれば、値をフィルタリングif
条件を1つ以上追加できます。
[<expression> for <element> in <iterable> if <condition>]
<iterable>
各<element>
について。 <condition>
がTrue
と評価された場合、 <expression>
(通常は<element>
関数)を返されたリストに追加します。
たとえば、これを使用して整数のシーケンスから偶数だけを抽出することができます。
[x for x in range(10) if x % 2 == 0]
# Out: [0, 2, 4, 6, 8]
上記のコードは次のものと同じです:
even_numbers = []
for x in range(10):
if x % 2 == 0:
even_numbers.append(x)
print(even_numbers)
# Out: [0, 2, 4, 6, 8]
また、( e
とc
はx
式である) [e for x in y if c]
形式の条件付きリストの理解は、 list(filter(lambda x: c, map(lambda x: e, y)))
。
同じ結果を出すにもかかわらず、前者の例が後者の例よりもほぼ2倍速いという事実に注意してください。好奇心を抱く人にとって、 これは理由のすてきな説明です。
これはかなり異なっていることに注意してください... if ... else ...
(時にはとして知られている条件式三元表現あなたが使用することができます) <expression>
リストの内包の一部。次の例を考えてみましょう。
[x if x % 2 == 0 else None for x in range(10)]
# Out: [0, None, 2, None, 4, None, 6, None, 8, None]
ここで条件式はフィルタではなく、リストアイテムに使用される値を決定する演算子です。
<value-if-condition-is-true> if <condition> else <value-if-condition-is-false>
これは、他の演算子と組み合わせるとより明白になります。
[2 * (x if x % 2 == 0 else -1) + 1 for x in range(10)]
# Out: [1, -1, 5, -1, 9, -1, 13, -1, 17, -1]
あなたは、Python 2.7を使用している場合、 xrange
より良いかもしれrange
で説明したように、いくつかの理由でxrange
ドキュメント 。
[2 * (x if x % 2 == 0 else -1) + 1 for x in xrange(10)]
# Out: [1, -1, 5, -1, 9, -1, 13, -1, 17, -1]
上記のコードは次のものと同じです:
numbers = []
for x in range(10):
if x % 2 == 0:
temp = x
else:
temp = -1
numbers.append(2 * temp + 1)
print(numbers)
# Out: [1, -1, 5, -1, 9, -1, 13, -1, 17, -1]
三項式とif
条件を組み合わせることができます。三項演算子はフィルタリングされた結果に作用します:
[x if x > 2 else '*' for x in range(10) if x % 2 == 0]
# Out: ['*', '*', 4, 6, 8]
同じことは三元演算子だけでは達成できませんでした:
[x if (x > 2 and x % 2 == 0) else '*' for x in range(10)]
# Out:['*', '*', '*', '*', 4, '*', 6, '*', 8, '*']
関連項目:条件付きリスト内包表記に十分な代替案を提供するフィルタ 。
ネストループを使用したリストの理解
List Comprehensionはfor
ループをネストfor
使用できます。リスト内包の中で任意の数のネストされたforループをコーディングすることができます。また、 for
ループごとfor
オプションの関連if
テストがあります。そうするとき、 for
構文の順序は、一連の入れ子のfor
文を書くときと同じ順序です。 list comprehensionsの一般的な構造は次のようになります。
[ expression for target1 in iterable1 [if condition1]
for target2 in iterable2 [if condition2]...
for targetN in iterableN [if conditionN] ]
たとえば、複数のfor
文を使用してリストのリストをフラット化する次のコードは、
data = [[1, 2], [3, 4], [5, 6]]
output = []
for each_list in data:
for element in each_list:
output.append(element)
print(output)
# Out: [1, 2, 3, 4, 5, 6]
は、複数のfor
構文を持つリストの理解として等価的に書くことができます。
data = [[1, 2], [3, 4], [5, 6]]
output = [element for each_list in data for element in each_list]
print(output)
# Out: [1, 2, 3, 4, 5, 6]
展開された形式とリストの理解の両方で、外側のループ(最初のforステートメント)が最初に来ます。
よりコンパクトであることに加えて、ネストされた理解度もかなり速くなります。
In [1]: data = [[1,2],[3,4],[5,6]]
In [2]: def f():
...: output=[]
...: for each_list in data:
...: for element in each_list:
...: output.append(element)
...: return output
In [3]: timeit f()
1000000 loops, best of 3: 1.37 µs per loop
In [4]: timeit [inner for outer in data for inner in outer]
1000000 loops, best of 3: 632 ns per loop
上記の関数呼び出しのオーバーヘッドは約140nsです。
インラインif
sは同様にネストされ、そして第一後の任意の位置で起こり得るfor
:
data = [[1], [2, 3], [4, 5]]
output = [element for each_list in data
if len(each_list) == 2
for element in each_list
if element != 5]
print(output)
# Out: [2, 3, 4]
ただし、読みやすくするために、従来のforループを使用することを検討する必要があります 。これは、ネスティングが2レベル以上深く、かつ/または理解の論理が複雑すぎる場合に特に当てはまる。複数のネストされたループリストの理解がエラーを起こしやすいか、または予期しない結果をもたらす可能性があります。
リファクタリングフィルタとリスト内包表へのマップ
filter
関数またはmap
関数は、多くの場合、 リスト内包表記に置き換えてください 。グイド・ヴァン・ロッサム(Guido Van Rossum)は、2005年の公開書簡でこれをよく説明している。
filter(P, S)
は、ほとんどの場合、[x for x in S if P(x)]
ように[x for x in S if P(x)]
明示され、これは、最も一般的な用途では、x==42
比較述語を伴うという大きな利点があります。ラムダは読者にとってはるかに多くの労力を要します(ラムダはリストの理解よりも遅いです)。さらにmap(F, S)
は[F(x) for x in S]
map(F, S)
[F(x) for x in S]
ます。もちろん、多くの場合、代わりにジェネレータ式を使用することができます。
次のコード行は " 非python "とみなされ、多くのpython lintersでエラーが発生します。
filter(lambda x: x % 2 == 0, range(10)) # even numbers < 10
map(lambda x: 2*x, range(10)) # multiply each number by two
reduce(lambda x,y: x+y, range(10)) # sum of all elements in list
前回の見積もりから学んだことを踏まえ、これらのfilter
とmap
式を同等のリスト内包表記に分解することができます。 ラムダ関数をそれぞれから削除する - プロセス内でコードをより読みやすくする。
# Filter:
# P(x) = x % 2 == 0
# S = range(10)
[x for x in range(10) if x % 2 == 0]
# Map
# F(x) = 2*x
# S = range(10)
[2*x for x in range(10)]
連鎖機能を扱う際の可読性はさらに顕著になります。読みやすさのために、1つのマップまたはフィルタ関数の結果を次の結果に渡す必要があります。単純なケースでは、これらを単一のリストの理解に置き換えることができます。さらに、連鎖したMap&Filterプロセスについて推論する際に、認知負荷が増えているプロセスの結果が何であるかをリストの理解から容易に知ることができます。
# Map & Filter
filtered = filter(lambda x: x % 2 == 0, range(10))
results = map(lambda x: 2*x, filtered)
# List comprehension
results = [2*x for x in range(10) if x % 2 == 0]
リファクタリング - クイックリファレンス
地図
map(F, S) == [F(x) for x in S]
フィルタ
filter(P, S) == [x for x in S if P(x)]
ここで、 F
とP
はそれぞれ入力値を変換してbool
を返す関数です
入れ子リストの理解
ネストされたリスト内包表記は、ネストされたループを持つリスト内包表記とは異なり、リスト内包表記内のリスト内包表記です。最初の式は、別のリストの理解を含む任意の式にすることができます。
#List Comprehension with nested loop
[x + y for x in [1, 2, 3] for y in [3, 4, 5]]
#Out: [4, 5, 6, 5, 6, 7, 6, 7, 8]
#Nested List Comprehension
[[x + y for x in [1, 2, 3]] for y in [3, 4, 5]]
#Out: [[4, 5, 6], [5, 6, 7], [6, 7, 8]]
入れ子の例は、
l = []
for y in [3, 4, 5]:
temp = []
for x in [1, 2, 3]:
temp.append(x + y)
l.append(temp)
ネストされた理解を使用して行列を転置することができる1つの例。
matrix = [[1,2,3],
[4,5,6],
[7,8,9]]
[[row[i] for row in matrix] for i in range(len(matrix))]
# [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
ネストされたfor
ループのように、深い解説がどのようにネストできるかに制限はありません。
[[[i + j + k for k in 'cd'] for j in 'ab'] for i in '12']
# Out: [[['1ac', '1ad'], ['1bc', '1bd']], [['2ac', '2ad'], ['2bc', '2bd']]]
リスト内包の中で2つ以上のリストを同時に反復する
リストの理解の中で2つ以上のリストを同時に反復するには、 zip()
を次のように使用します。
>>> list_1 = [1, 2, 3 , 4]
>>> list_2 = ['a', 'b', 'c', 'd']
>>> list_3 = ['6', '7', '8', '9']
# Two lists
>>> [(i, j) for i, j in zip(list_1, list_2)]
[(1, 'a'), (2, 'b'), (3, 'c'), (4, 'd')]
# Three lists
>>> [(i, j, k) for i, j, k in zip(list_1, list_2, list_3)]
[(1, 'a', '6'), (2, 'b', '7'), (3, 'c', '8'), (4, 'd', '9')]
# so on ...