Pythonのリスト理解-包括的なガイド


Pythonのリストの理解は、強力な読み取り可能なリストの変異を可能にします.この記事では、彼らはどのように使用することができますし、彼らが最も有用である方法で多くの異なる方法を学びます.
Pythonは広範囲にわたるアプリケーションに広く採用されている非常に強力な言語です.十分な複雑さのどんな言語と同様に、Pythonは物事を行う複数の方法を可能にします.しかし、コミュニティは、コードが特定のパターンに従うべきであることに同意しました:「パイソン」であってください.「Parthonic」がコミュニティ用語である間、公用語は彼らが呼ぶものを定義します“The Zen of Python” in PEP 20 . ほんの少しだけ引用する

Explicit is better than implicit.

Simple is better than complex.

Complex is better than complicated.

Flat is better than nested.


Python 2.0で導入されましたPEP 202 , リスト理解は、Pythonで一般的な操作のためにこれらのゴールのいくらかを整列させるのを助けます.どのようにリストの理解を使用することができますし、彼らは代替のよりもPythonの禅を提供する方法を探る.

リスト理解とは何か


我々が0から2まで数えて、数の配列を作りたいと言いましょう.空の配列を割り当てることができますrange ジェネレータを作成するにはappend を使用する配列for ループ
numbers = []
for x in range(3):
    numbers.append(x)
代わりに、リストの理解を使用して1行のコードに短縮できます.
numbers = [x for x in range(3)]
構文に混乱?トークンで何が起こっているのか説明しましょう.
Breakdown of a list comprehension explained more below
最初と最後のブラケットは、単にこれがリスト理解であることを示します.これはリストの理解が配列を出力していることを覚えています.
第二に、“for”の前に“x”があります.これが返り値です.つまり、以下のように理解を変えることができます.
numbers = [x*2 for x in range(3)]
"0 , 1 , 2 "の代わりに"0 , 2 , 4 "を得る.
次に、我々はAの宣言をしますfor ループ.これは3つの部分からなる.
  • ループの開始
  • "x "-各繰り返しで割り当てる変数の名前を宣言する
  • "in "-イテレータのリスニングの開始を表す
  • 最後に、我々はrange . これはfor ループを繰り返します.これは何でも構いませんfor ループを通過することができます:リスト、タプル、またはイテレータインターフェイスを実装する何か.

    リスト理解パイソン


    リストを操作するための新しい構文を学ぶのは直感的に思えるかもしれませんが、選択肢がどのように見えるかを見てみましょう.使用map , 我々は匿名関数(λ)を渡すことができますrange を繰り返す.しかし、これが行われると、私たちはmap オブジェクト.このリストをリストに変換するには、list .
    numbers = list(map(lambda x: x*2, range(3)))
    
    これをリスト理解版と比較してください.
    numbers = [x*2 for x in range(3)]
    
    理解を見て、それは一目でかなり読みやすいです.Pythonの禅に考えて、“単純な複雑よりも優れている”リストの理解は、よりもPythonのように見えるmap .
    他の人は「for」ループが読むのがより簡単であるかもしれないと主張するかもしれませんが、PythonのZenも「入れ子よりよく平らです」と言及します.このため、このような簡単な使い方のリストの理解はよりピタニックです.
    リストの理解の基本的な使い方に慣れているので、いくつかの強力な機能に飛び込みましょう.

    フィルタリング


    リストの理解が1 : 1のようなマッチをするだけであるように見えるかもしれませんがmap , 実際には、次のようなロジックを実装することができますfilter 入力されたものと比較して出力に何個の項目があるかを変更します.
    我々が加えるならばif ステートメントの最後には、出力を偶数に制限することができます.
    even_numbers = [x for x in range(10) if x%2==0] #[0, 2, 4, 6, 8]
    
    これはもちろん変更された変異値と組み合わせることができます.
    double_even_numbers = [x*2 for x in range(10) if x%2==0] #[0, 4, 8, 12, 16]
    

    条件


    フィルタリングは、if リストの理解において、あなたはそれらを使用して、異なる値を元の値から返すよう条件付けを行うことができます.
    number_even_odd = ["Even" if x % 2 == 0 else "Odd" for x in range(4)]
    # ["Even", "Odd", "Even", "Odd"]
    
    この3進法を以前のフィルタリングと組み合わせることもできますif :
    thirds_even_odd = ["Even" if x % 2 == 0 else "Odd" for x in range(10) if x%3==0]
    # [0, 3, 6, 9] after filtering numbers
    # ["Even", "Odd", "Even", "Odd"] after ternary to string
    
    このコードを拡張してフルボディ関数を使用したいなら、次のようになります.
    thirds_even_odd = []
    for x in range(10):
        if x%3==0:
            if x%2==0:
                thirds_even_odd.append("Even")
            else:
                thirds_even_odd.append("Odd")
    

    入れ子ループ


    私たちは私たちの“フィルタリング”セクションの入力よりも出力の少ない項目を持つことができることを説明したが、あなたは同様に反対を行うことができます.ここでは、我々の最初の入力より長い出力を持つために、互いの上に2つの「for」ループをネストすることができます.
    repeated_list = [y for x in ["", ""] for y in [1, 2, 3]]
    # [1, 2, 3, 1, 2, 3]
    
    このロジックでは、2つの異なる配列を反復処理し、入れ子になったループの最終値を出力できます.これを書き直す必要があるなら、以下のように書きます:
    repeated_list = []
    for x in ["", ""]:
        for y in [1, 2, 3]:
            repeated_list.append(y)
    
    これは、ループをネストし、ロジックを平らに保つことができます.しかし、この例では“x”変数を利用していないことに気づくでしょう.それを変えて、「x」変数に基づいて計算をしましょう:
    numbers_doubled = [y for x in [1, 2] for y in [x, x*2]]
    # 1, 2, 2, 4
    
    ネストループにハードコード化された配列を使用したので、1つのレベルを深くしましょう.入れ子状の方法でリストの理解をどのように利用できるかを見てみましょう.

    入れ子の理解


    私たちがスーパーパワーでリスト理解を提供するために結合することができる2つの事実があります:
  • リストの理解の中でリストを使用することができます
  • リスト理解リストを返す
  • これらのリードを組み合わせて、自然の結論には、他のリストの理解の内部のリストの理解をネストすることができます.
    たとえば、2次元リストを指定すると、1つのリストの第1のインデックス項目と2番目のインデックス項目の2番目のリストのすべてを返す、次のロジックを取りましょう.
    row_list = [[1, 2], [3,4], [5,6]]
    indexed_list = []
    for i in range(2):
        indexed_row = []
        for row in row_list:
            indexed_row.append(row[i])
        indexed_list.append(indexed_row)
    
    print(indexed_list)
    # [[1, 3, 5], [2, 4, 6]]
    
    あなたは、最初のインデックスアイテム(1 , 3 , 5 ) は最初の配列、2番目のインデックス項目(2 , 4 , 6 ) は2番目の配列にある.
    それをしてリスト理解に変換しましょう.
    row_list = [[1, 2], [3,4], [5,6]]
    indexed_list = [[row[i] for row in row_list] for i in range(2)]
    print(indexed_list)
    # [[1, 3, 5], [2, 4, 6]]
    

    読みやすさと他の演算子


    リスト理解で働いている間、あなたが気づいたかもしれない何かは、これらのオペレーターのいくらかが典型的な文にどれくらい近いかです.基本的な理解は、このよく自分自身にサービスを提供しながら、彼らはPythonの他の文法スタイルの演算子のようなものによって進めている.例えば、演算子を含めることができます.
  • and - 論理", "
  • or - 論理"OR "
  • not - 論理"not "
  • is - 等値チェック
  • in - メンバーシップチェックfor ループ
  • これらは大きな効果のために使用することができます.いくつかのオプションを見てみましょう.
    vowels = 'aeiou'
    word = "Hello!"
    
    word_vowels = [letter for letter in word if letter.lower() in vowels]
    
    print(word_vowels)
    
    # ['e', 'o']
    
    代わりに子音をチェックすることもできます.
    word_consonants = [letter for letter in word if letter.lower() not in vowels]
    # ['H', 'l', 'l']
    
    最後に、Showcase Boolean Logicでは、mod 2と3が完全には4ではない数字についてのわずかな工夫を行います.
    restricted_number = 4
    
    safe_numbers = [x for x in range(6) if (x%2==0 or x%3==0) and x is not restricted_number]
    
    # [0, 2, 3]
    

    結論と挑戦


    我々は、今日のPythonでのリストの理解について多くをカバーしてきた!ほとんどの状況で読みやすさを維持しながら、我々は複雑なロジックをアプリケーションに組み込むことができます.しかし、任意のツールのように、リストの理解を悪用することができます.あなたが快適に読むためにあまりにも多くの論理的な操作を開始すると、あなたはfor ループ.
    たとえば、長いと厄介なリストの理解のこのサンドボックスのコードパッドを考えると、どのようにリストの理解のすべての使用法を削除するリファクタリングできますか?避けるmap , filter またはその他のリストヘルパー.単にネストするfor ループとif 条件は、以前のように動作に一致する.
    See the code challenge here
    これは、オープンエンドの質問は、記事を通して学んだあなたのスキルに挑戦することを意味です!
    スタック?あなたのソリューションを共有したいですか?Join our community Slack , どこでリストの理解と深さの挑戦cocopadチームと話すことができます!