| パート1 | パート2 | パート3 | パート4 | 
|---|
 私のサイクルの最後の部分は、コレクションの操作に参加しました。 この記事は独立しており、以前の記事の予備調査なしで調査できます。 
      この記事は、以前の記事よりも深く詳細であるため、初心者だけでなく、経験豊富なPython開発者にとっても興味深いものになります。
  考慮されます:式ジェネレーター、リスト、辞書およびセットジェネレーター、ネストされたジェネレーター(5つのオプション)、enumerate()、range()で動作します。 
      また、分類と用語、構文、サイクル形式の類似物、およびアプリケーションの例。
 私はすべての本やコースでカバーされていない微妙さとニュアンスを考慮しようとしました。特に、Habrahabrですでに公開されているこの主題に関する記事には欠けています。 
      目次:
1. 定義と分類。
2. 構文。
3. forループの形式と関数の形式のアナログ。
4. 式ジェネレータ。
5. 標準コレクションの生成。
6. 頻度および部分検索。
7. ネストされたループとジェネレーター。
8. 範囲()を使用します。
9. 付録1.追加の例。
10. 付録2.関連リンク。
1.定義と分類
1.1何と理由
- 式ジェネレータは、要素のコレクションを生成し、あるタイプのコレクションを別のタイプに変換するコンパクトで便利な方法のために設計されています。
 - 生成または変換のプロセスでは、条件を適用して要素を変更することができます。
 - 式ジェネレーターは構文糖衣であり、使用しないと解決できない問題を解決しません。
 
1.2式ジェネレータを使用する利点
- 通常のループでの生成よりも短くて便利な構文。
 - map()、filter()、およびlambda関数の同時使用を組み合わせた機能的アナログよりも理解しやすく読みやすい構文。
 - 一般に、特にコード内に同様の操作が多数ある場合は、タイピングが速く、読みやすくなります。
 
1.3分類と機能
私たちが話そうとしていることのロシア語の名前には、いくつかの用語の混乱があるとすぐに言わなければなりません。
この記事では次の表記法を使用しています。
- ジェネレーター式-生成される括弧内の式は、各反復で規則に従って新しい要素を作成します。
 - コレクションジェネレータ -リスト内包ジェネレータ、辞書内包ジェネレータ、集合内包ジェネレータの総称。
 

一部の場所では、用語のヒープを回避するために、「ジェネレーター」という用語をさらに明確にせずに使用します。
2.構文
まず、ジェネレータ式の一般的な構文の図を示します。
重要 :この構文は、ジェネレーター式と3種類のコレクションジェネレーターすべてで同じです。違いは、括弧で囲むことです(前の図を参照)。

理解に重要な一般原則:
- 入力はイテレータです。ジェネレータ関数、式ジェネレータ、コレクションなどがあり、その反復をサポートするオブジェクトです。
 - 条件は、要素が最終的な式に入るフィルターであり、要素がそれを満たさない場合はスキップされます。
 - 最終式は、選択された各アイテムを出力前に変換したもの、または単に変更せずに出力したものです。
 
2.1基本構文
list_a = [-2, -1, 0, 1, 2, 3, 4, 5] #       list_b = [x for x in list_a] #       print(list_b) # [-2, -1, 0, 1, 2, 3, 4, 5] print(list_a is list_b) # False -   !
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
      実際、ここでは興味深いことは何も起こりませんでした。リストのコピーを取得しただけです。 そのようなコピーを作成するか、単にジェネレーターを使用してコレクションを型から型に抽出することは意味がありません-これは、コレクションを作成するための適切なメソッドまたは関数を使用することではるかに簡単に行うことができます(シリーズの最初の記事で説明)
式ジェネレータの威力は、新しいコレクションに要素を含めるための条件を設定でき、その出力(新しいコレクションに含める)の前に式または関数を使用して現在の要素の変換を実行できるという事実にあります。
2.2フィルタリングの条件を追加する
重要 :条件は各反復でチェックされ、条件を満たす要素のみが式の処理に進みます。
前の例に条件を追加します-偶数の要素のみを取得します。
 # if x % 2 == 0 -     2   -   list_a = [-2, -1, 0, 1, 2, 3, 4, 5] list_b = [x for x in list_a if x % 2 == 0] print(list_b) # [-2, 0, 2, 4]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      いくつかの条件を使用して、それらを論理演算子と組み合わせます 。
 list_a = [-2, -1, 0, 1, 2, 3, 4, 5] list_b = [x for x in list_a if x % 2 == 0 and x > 0] #   x,       print(list_b) # [2, 4]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      2.3式に要素処理を追加する
フィルターを通過した現在の要素ではなく、それを使用して式を評価した結果、または関数によるその処理の結果を挿入できます。
重要 :式は各反復で独立して実行され、各要素を個別に処理します。
たとえば、各要素の値の二乗を計算できます。
 list_a = [-2, -1, 0, 1, 2, 3, 4, 5] list_b = [x**2 for x in list_a] print(list_b) # [4, 1, 0, 1, 4, 9, 16, 25]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      または、len()関数を使用して文字列の長さをカウントします
 list_a = ['a', 'abc', 'abcde'] list_b = [len(x) for x in list_a] print(list_b) # [1, 3, 5]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      2.4分岐式
注:式で(Python 2.5以降) if-elseコンストラクトを使用して、最終式を分岐できます 。
この場合:
- 分岐条件は、イテレータの後ではなく前に書き込まれます。
 - この場合、if-elseは式を実行する前のフィルターではなく、式自体の分岐です。つまり、変数は既にフィルターを通過していますが、条件に応じてさまざまな方法で処理できます。
 
 list_a = [-2, -1, 0, 1, 2, 3, 4, 5] list_b = [x if x < 0 else x**2 for x in list_a] #  x- -  x,    -   x print(list_b) # [-2, -1, 0, 1, 4, 9, 16, 25]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      フィルタリングと分岐の組み合わせを禁止する人はいません。
 list_a = [-2, -1, 0, 1, 2, 3, 4, 5] list_b = [x**3 if x < 0 else x**2 for x in list_a if x % 2 == 0] #         #          ,      print(list_b) # [-8, 0, 4, 16]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
        同じループの例 
       list_a = [-2, -1, 0, 1, 2, 3, 4, 5] list_b = [] for x in list_a: if x % 2 == 0: if x < 0: list_b.append(x ** 3) else: list_b.append(x ** 2) print(list_b) # [-8, 0, 4, 16]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      2.5読みやすさの改善
Pythonの構文では、括弧内で改行を使用できることを忘れないでください。 この機能を使用すると、式ジェネレーターの構文を読みやすくすることができます。
 numbers = range(10) # Before squared_evens = [n ** 2 for n in numbers if n % 2 == 0] # After squared_evens = [ n ** 2 for n in numbers if n % 2 == 0 ]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
      3. forループの形式と関数の形式のアナログ
前述のように、式ジェネレータを使用して解決されたタスクは、それらがなくても解決できます。 同じ問題を解決するために使用できる他のアプローチを次に示します。
たとえば、簡単なタスクを見てみましょう。数字のリストから偶数の正方形のリストを作成し、3つの異なるアプローチを使用してそれを解きます。
3.1リストジェネレーターを使用したソリューション
 numbers = range(10) squared_evens = [n ** 2 for n in numbers if n % 2 == 0] print(squared_evens) # [0, 4, 16, 36, 64]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
      3.2。 forループを使用したソリューション
重要 :各式ジェネレーターはforループとして書き直すことができますが、すべてのforループをそのような式として表すことはできません。
 numbers = range(10) squared_evens = [] for n in numbers: if n % 2 == 0: squared_evens.append(n ** 2) print(squared_evens) # [0, 4, 16, 36, 64]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
      一般に、非常に複雑で複雑なタスクの場合、サイクルの形のソリューションは、より理解しやすく、保守と調整が容易です。 単純なタスクの場合、ジェネレータ式の構文はよりコンパクトで読みやすくなります。
3.3。 関数を使用したソリューション。
まず、式ジェネレーターとコレクションジェネレーターも機能的なスタイルですが、より新しく、より望ましいスタイルであることに注意してください。
map()、lambdaおよびfilter()を組み合わせることにより、古い機能的アプローチを適用して同じ問題を解決できます。
 numbers = range(10) squared_evens = map(lambda n: n ** 2, filter(lambda n: n % 2 == 0, numbers)) print(squared_evens) # <map object at 0x7f661e5dba20> print(list(squared_evens)) # [0, 4, 16, 36, 64] # :  Python 2   squared_evens   ,   Python 3 «map object»,        list()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
      そのような例は非常に機能しているという事実にもかかわらず、読むことは難しく、式ジェネレーターの構文を使用することはより望ましいと理解できるでしょう。
4.ジェネレーター式
ジェネレーター式は、Python 2.4以降で使用可能です。 コレクションジェネレーターとの主な違いは、コレクション全体を一度にメモリにロードすることなく、一度に1つの要素を発行することです。
UPD:もう一度、この点に注意してください:ジェネレーターを使用せずに大きなデータ構造を作成すると、それぞれメモリ全体にロードされるため、アプリケーションのメモリ消費量が増加し、極端な場合、メモリが十分ではなく、アプリケーションが「クラッシュ」します»MemoryErrorあり 。 ジェネレータ式を使用する場合、要素は一度に1つずつ、処理時に作成されるため、これは発生しません。
ジェネレーター式の例:
 list_a = [-2, -1, 0, 1, 2, 3, 4, 5] my_gen = (i for i in list_a) # - print(next(my_gen)) # -2 -     print(next(my_gen)) # -1 -    
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
      ジェネレーター式の機能
-   括弧なしでジェネレータを書くことはできません -これは構文エラーです。 
      
# my_gen = i for i in list_a # SyntaxError: invalid syntax
 -  関数に渡すとき、追加の括弧はオプションです 
      
list_a = [-2, -1, 0, 1, 2, 3, 4, 5] my_sum = sum(i for i in list_a) # my_sum = sum((i for i in list_a)) # print(my_sum) # 12
 -   len ()関数で長さを取得できません 
      
# my_len = len(i for i in list_a) # TypeError: object of type 'generator' has no len()
 -   print ()で要素を印刷できません 
      
print(my_gen) # <generator object <genexpr> at 0x7f162db32af0>
 -  式ジェネレータを通過した後、 空のままになることに注意してください! 
      
list_a = [-2, -1, 0, 1, 2, 3, 4, 5] my_gen = (i for i in list_a) print(sum(my_gen)) # 12 print(sum(my_gen)) # 0
 -  ジェネレータ式は無限にすることができます。 
      
そのようなジェネレーターを使用するときは注意してください。正しく使用しないと、「効果」は無限ループのようになります。import itertools inf_gen = (x for x in itertools.count()) # 0 to !
 -  スライスはジェネレーター式には適用できません ! 
      
list_a = [-2, -1, 0, 1, 2, 3, 4, 5] my_gen = (i for i in list_a) my_gen_sliced = my_gen[1:3] # TypeError: 'generator' object is not subscriptable
 - ジェネレーターから、 目的のコレクションを簡単に取得できます 。 これについては、次の章で詳しく説明します。
 
5.標準コレクションの生成
5.1ジェネレーター式からコレクションを作成する
list()、tuple()、set()、frozenset()関数を使用してジェネレーター式からコレクションを作成する
注 :この方法では、生成後に不変になるため、不変セットとタプルの両方を作成できます。
注 :文字列の場合、このメソッドは機能しません! この方法でディクショナリジェネレータを作成する構文には独自の特性があり、次のサブセクションで検討します。
-  割り当てられた変数の完成したジェネレーター式をコレクション作成関数に渡します。 
      
list_a = [-2, -1, 0, 1, 2, 3, 4, 5] my_gen = (i for i in list_a) # - my_list = list(my_gen) print(my_list) # [-2, -1, 0, 1, 2, 3, 4, 5]
 -  呼び出された関数の括弧内にジェネレーター式を直接記述して、コレクションを作成します。 
      
list_a = [-2, -1, 0, 1, 2, 3, 4, 5] my_list = list(i for i in list_a) print(my_list) # [-2, -1, 0, 1, 2, 3, 4, 5]
タプル、多数、および不変の多数についても同じことが言えます。# my_tuple = tuple(i for i in list_a) print(my_tuple) # (-2, -1, 0, 1, 2, 3, 4, 5) # my_set = set(i for i in list_a) print(my_set) # {0, 1, 2, 3, 4, 5, -1, -2} # my_frozenset = frozenset(i for i in list_a) print(my_frozenset) # frozenset({0, 1, 2, 3, 4, 5, -1, -2})
 
5.2特別なコレクションジェネレーターの構文
コレクション全体をメモリにロードせずに1つずつ値を生成するジェネレーター式とは異なり、コレクションジェネレーターを使用すると、コレクション全体がすぐに生成されます。
したがって、上記の特定の式ジェネレータの代わりに、このようなコレクションには、このタイプのコレクションに特徴的なすべての標準プロパティが含まれます。
セットとディクショナリの生成には同じブラケットが使用されることに注意してください。違いは、ディクショナリにdouble要素のkey:valueがあることです。
-   リスト内包表記ジェネレータ 
      
list_a = [-2, -1, 0, 1, 2, 3, 4, 5] my_list = [i for i in list_a] print(my_list) # [-2, -1, 0, 1, 2, 3, 4, 5]
括弧を四角で書かないでください!
list_a = [-2, -1, 0, 1, 2, 3, 4, 5] my_list = [(i for i in list_a)] print(my_list) # [<generator object <genexpr> at 0x7fb81103bf68>]
 -  内包表記ジェネレーターを設定する 
      
list_a = [-2, -1, 0, 1, 2, 3, 4, 5] my_set= {i for i in list_a} print(my_set) # {0, 1, 2, 3, 4, 5, -1, -2} -
 -   辞書理解 
      
辞書反転
dict_abc = {'a': 1, 'b': 2, 'c': 3, 'd': 3} dict_123 = {v: k for k, v in dict_abc.items()} print(dict_123) # {1: 'a', 2: 'b', 3: 'd'} # , ""! , # , .
リストからの辞書:
list_a = [-2, -1, 0, 1, 2, 3, 4, 5] dict_a = {x: x**2 for x in list_a} print(dict_a) # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16, -2: 4, -1: 1, 5: 25}
重要 ! このようなディクショナリ作成構文は中括弧でのみ機能し、 ジェネレータ式はこのように作成できません。これにはわずかに異なる構文が使用されます(コメントのヘルプのlongclapsに感謝します)。
# dict_gen = (x: x**2 for x in list_a) # SyntaxError: invalid syntax dict_gen = ((x, x ** 2) for x in list_a) # - # dict_a = dict(x: x**2 for x in list_a) # SyntaxError: invalid syntax dict_a = dict((x, x ** 2) for x in list_a) # @longclaps
 
5.3ライン生成
式ジェネレータの構文の代わりに、文字列メソッドを使用して文字列を作成します。 ジェネレーター式を引数として渡すことができるjoin ()。
ご注意ください :コレクションアイテムは、文字列に結合される文字列でなければなりません!
 list_a = [-2, -1, 0, 1, 2, 3, 4, 5] #     .join()       my_str = ''.join(str(x) for x in list_a) print(my_str) # -2-1012345
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
      6.頻度と部分検索
6.1 enumerate()の使用
フィルター条件のタスクの条件では、現在の要素の値を確認する必要はありませんが、特定の頻度を確認する必要があります。たとえば、3つおきの要素を取得する必要があります。
そのようなタスクには、ループ内でイテレーターを反復処理するときにカウンターを設定するenumerate()関数を使用できます。
 for i, x in enumerate(iterable)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      ここで、xは現在の要素iはゼロから始まるシリアル番号です 
      インデックスの動作を説明しましょう:
 list_a = [-2, -1, 0, 1, 2, 3, 4, 5] list_d = [(i, x) for i, x in enumerate(list_a)] print(list_d) # [(0, -2), (1, -1), (2, 0), (3, 1), (4, 2), (5, 3), (6, 4), (7, 5)]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
      さて、実際の問題を解決してみましょう-元のリストからリストジェネレーターの3番目の要素をすべて選択します。
 list_a = [-2, -1, 0, 1, 2, 3, 4, 5] list_e = [x for i, x in enumerate(list_a, 1) if i % 3 == 0] print(list_e) # [0, 3]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
      enumerate()関数の重要な機能:
-   enumerate()関数を呼び出すための2つのオプションがあります。 
- 2番目のパラメーターなしの列挙(イテレーター)は0からカウントされます。
 - enumerate(iterator、start)-startの値からカウントを開始します。 たとえば、0ではなく1からカウントする必要がある場合に便利です。
 
 -   enumerate()は、現在の反復子要素のシリアル番号と値のタプルを返します。 式ジェネレータの結果のタプルは、次の2つの方法で取得できます。 
- (i、j)for i、j in enumerate(反復子)-最初のペアの括弧が必要です!
 - 列挙内のペアのペア(mylist)-すぐにカップルで作業します
 
 -  インデックスは、後で条件を渡したかどうかに関係なく、 処理されたすべての要素に対して考慮されます ! 
      
first_ten_even = [(i, x) for i, x in enumerate(range(10)) if x % 2 == 0] print(first_ten_even) # [(0, 0), (2, 2), (4, 4), (6, 6), (8, 8)]
 -   enumerate()関数はコレクションの一部の内部属性にアクセスせず、処理された要素のカウンターを実装するだけです。したがって、インデックス付けされていない順序付けられていないコレクションに使用されることを妨げるものはありません。 
      
 - enumerate()カウンターによって結果に含まれる要素の数を制限する場合(たとえば、i <10の場合)、イテレーターは完全に処理されますが、巨大なコレクションの場合は非常にリソースを消費します。 この問題の解決策については、サブセクション「反復可能な部分の列挙」で説明します。
 
6.2反復可能部分の列挙。
場合によっては、条件を満たす非常に大きなコレクションまたは無限のジェネレーターからタスクがあり、条件を満たす最初のいくつかの要素を選択することがあります。
enumerate()インデックスまたは結果の結果のコレクションのスライスに制限の条件を持つ正規のジェネレーター式を使用する場合、いずれにしても、巨大なコレクション全体を調べて、これに多くのコンピューターリソースを費やす必要があります。
解決策は、 itertoolsパッケージのislice()関数を使用することです。
 import itertools first_ten = (itertools.islice((x for x in range(1000000000) if x % 2 == 0), 10)) print(list(first_ten)) # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
        疑わしい人のために:ランタイムをチェック 
       import time import itertools #       start_time = time.time() first_ten = (itertools.islice((x for x in range(100) if x % 2 == 0), 10)) print(list(first_ten)) # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18] elapsed_time = time.time() - start_time print(elapsed_time) # 3.409385681152344e-05 #       start_time = time.time() first_ten = (itertools.islice((x for x in range(100000000) if x % 2 == 0), 10)) print(list(first_ten)) # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18] elapsed_time = time.time() - start_time print(elapsed_time) # 1.1205673217773438e-05 #        range()    6 , #       
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     7.ネストされたループとジェネレーター
この場合、ループまたは式ジェネレータ自体がネストされている場合、より複雑なオプションを考えてみましょう。 ここでは、独自の特性と範囲を持ついくつかのオプションが可能であるため、混乱しないように、それらを個別に検討し、その後、一般的なスキームを示します。
7.1ネストされたループ
生成の結果、 1次元の構造が得られます。
重要 ! 式ジェネレーター内でネストされたループを操作する場合、for in命令は、ジェネレーターを使用しない同様のソリューションと同じ順序(左から右)に従い、ループ上(上から下)でのみ実行されます! 同じことは、より深いレベルのネストにも当てはまります。
7.1.1ループが独立した反復子を通過するループの入れ子
一般構文: [iter2のyのiter1のxの式]
アプリケーション :2つの反復子からのデータを使用して1次元構造を生成します。
たとえば、座標タプルをキーとして使用してディクショナリを作成し、値をゼロで埋めます。
 rows = 1, 2, 3 cols = 'a', 'b' my_dict = {(col, row): 0 for row in rows for col in cols} print(my_dict) # {('a', 1): 0, ('b', 2): 0, ('b', 3): 0, ('b', 1): 0, ('a', 3): 0, ('a', 2): 0}
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
        その後、新しい値を設定するか、取得することができます 
       my_dict['b', 2] = 10 #     - print(my_dict['b', 2]) # 10 -     -
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      各サイクルで追加のフィルター条件を使用しても同じことができます。
 rows = 1, 2, 3, -4, -5 cols = 'a', 'b', 'abc' #       my_dict = { (col, row): 0 #     -    for row in rows if row > 0 #    for col in cols if len(col) == 1 #   } print(my_dict) # {('a', 1): 0, ('b', 2): 0, ('b', 3): 0, ('b', 1): 0, ('a', 3): 0, ('a', 2): 0}
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
        同じ問題がサイクルの助けを借りて解決しました。 
       rows = 1, 2, 3, -4, -5 cols = 'a', 'b', 'abc' my_dict = {} for row in rows: if row > 0: for col in cols: if len(col) == 1: my_dict[col, row] = 0 print(my_dict) # {('a', 1): 0, ('b', 2): 0, ('b', 3): 0, ('b', 1): 0, ('a', 3): 0, ('a', 2): 0}
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      7.1.2内側のループが外側のループの結果に従うループのネスト
一般的な構文: [xのyのイテレータのxの式] 。
アプリケーション :2次元のデータ構造をバイパスして、「フラットな」1次元に変換する必要がある場合の標準的なアプローチ。 この場合、外側のループのラインを通過し、内側のループで2次元構造の各行の要素を通過します。
2次元のマトリックス(リストのリスト)があるとします。 そして、それをフラットな一次元リストに変換したいと思います。
 matrix = [[0, 1, 2, 3], [10, 11, 12, 13], [20, 21, 22, 23]] #     : flattened = [n for row in matrix for n in row] print(flattened) # [0, 1, 2, 3, 10, 11, 12, 13, 20, 21, 22, 23]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
        ネストされたループを使用して解決された同じ問題 
       flattened = [] for row in matrix: for n in row: flattened.append(n) print(flattened)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        UPD:コメントからのエレガントなソリューション 
       import itertools flattened = list(itertools.chain.from_iterable(matrix)) #  @iMrDron #      #       . flattened = sum(a, []) #  @YuriM1983 # sum(a, [])   (O(n^2)) #          
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      7.2ネストされたジェネレーター
ジェネレーター式内のforループだけでなく、ジェネレーター自体もネストできます。
このアプローチは、2次元構造を構築する必要がある場合に使用されます。
重要 !:ネストされたループを使用した上記の例とは異なり、ネストされたジェネレーターでは、外部ジェネレーターが最初に処理され、次に内部ジェネレーター、つまり右から左に順番に処理されます。
以下では、この使用のための2つのオプションを検討します。
7.2.1-ジェネレーター内のネストされたジェネレーター-2次元の2つの1次元
一般的な構文: [[iter2のyの式] iter1のxの]
アプリケーション :2つの1次元イテレータのデータを使用して2次元構造を生成します。
たとえば、5列3行のマトリックスを作成し、ゼロで埋めます。
 w, h = 5, 3 #      matrix = [[0 for x in range(w)] for y in range(h)] print(matrix) # [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
        2つのネストされたループで同じマトリックスを作成する-ネストの順序に注意してください 
       matrix = [] for y in range(h): new_row = [] for x in range(w): new_row.append(0) matrix.append(new_row) print(matrix) # [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        注:作成後、通常の2次元配列と同様にマトリックスを操作できます 
       #       ( -    ) matrix[0][0] = 1 matrix[1][3] = 3 print(matrix) # [[1, 0, 0, 0, 0], [0, 0, 0, 3, 0], [0, 0, 0, 0, 0]] #      x, y = 1, 3 print(matrix[x][y]) # 3
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      7.2.2-ジェネレーター内のネストされたジェネレーター-2次元から2次元
一般的な構文: [イテレータのxの[xのyの式]]
アプリケーション :2次元データ構造を調べて、結果を別の2次元構造に保存します。
マトリックスを取る:
 matrix = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
      各行列要素を二乗します。
 squared = [[cell**2 for cell in row] for row in matrix] print(squared) # [[1, 4, 9, 16], [25, 36, 49, 64], [81, 100, 121, 144]]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
        ネストされたループと同じ操作 
       squared = [] for row in matrix: new_row = [] for cell in row: new_row.append(cell**2) squared.append(new_row) print(squared) # [[1, 4, 9, 16], [25, 36, 49, 64], [81, 100, 121, 144]]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     上記のすべてのオプションを1つのスキームにまとめます(クリックによるフルサイズ):
 
      7.3-ジェネレーターを反復処理するジェネレーター
ジェネレーターはforループでイテレーターとして使用できるため、ジェネレーターごとにジェネレーターを作成するためにも使用できます。
同時に、これは2つの式に構文的に記述したり、ネストしたジェネレーターに結合したりできます。
この可能性を説明します。
このようなリストジェネレーターが2つあるとします。
 list_a = [x for x in range(-2, 4)] #      , #       range(-2, 4) list_b = [x**2 for x in list_a]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
      list_aをリストジェネレーターに置き換えることで、同じことが1つの式に記述できます。
 list_c = [x**2 for x in [x for x in range(-2, 4)]] print(list_c) # [4, 1, 0, 1, 4, 9]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
      longclapsからのUPD:ジェネレーターを複素関数f(x)= u(v(x))の例と組み合わせる利点
 list_c = [t + t ** 2 for t in (x ** 3 + x ** 4 for x in range(-2, 4))]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
      8.範囲の使用()
コレクションを生成する方法について言えば、算術シーケンスを作成するために設計されたシンプルで非常に便利な関数範囲()を無視することはできません。
range()関数の特徴:
-  ほとんどの場合、必要な回数だけforループを開始するためにrange()関数が使用されます。 たとえば、上記の例のマトリックス生成を参照してください。 
      
 -   Python 3では、range()は、アクセスされるたびに次の要素を返すジェネレーターを返します。 
      
 -   使用されるパラメーターは 、スライスのパラメーターと似ています (1つのパラメーターを持つ最初の例を除く)。 
      
- 範囲(停止)-この場合、0から停止1まで。
 - 範囲(開始、停止)-上記の例と同様ですが、ゼロ以外の開始を指定できますが、負の値も指定できます。
 - 範囲(開始、停止、ステップ)-ステップパラメーターを追加します。負の値を指定して、逆の順序で繰り返します。
 
 - Python 2には2つの関数がありました:
      
- 範囲(...)は、Python 3の式リスト(範囲(...))に似ています。つまり、反復子は生成されず、すぐに作成できるリストが生成されます。つまり、セクション4で説明したメモリ不足の問題はすべて関連しており、Python 2で非常に慎重に使用する必要があります。
 - xrange(...)-Python 3のrange(...)と同様に機能し、バージョン3から除外されました。
 
 
使用例:
 print(list(range(5))) # [0, 1, 2, 3, 4] print(list(range(-2, 5))) # [-2, -1, 0, 1, 2, 3, 4] print(list(range(5, -2, -2))) # [5, 3, 1, -1]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
      9.付録1.追加の例
9.1いくつかのリストの順次通過
 import itertools l1 = [1,2,3] l2 = [10,20,30] result = [l*2 for l in itertools.chain(l1, l2)] print(result) # [2, 4, 6, 20, 40, 60]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      9.2マトリックス転置
(行が列と交換されるときのマトリックス変換)。マトリックスを取る。
 matrix = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
      式ジェネレータを使用して転置します。
 transposed = [[row[i] for row in matrix] for i in range(len(matrix[0]))] print(transposed) # [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
       サイクルの形でのマトリックスの同じ転置 
       transposed = [] for i in range(len(matrix[0])): new_row = [] for row in matrix: new_row.append(row[i]) transposed.append(new_row) print(transposed) # [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      そして、@ longclapsからのちょっとした黒魔術 
       transposed = list(map(list, zip(*matrix))) print(transposed) # [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     9.3営業日のみを選択するタスク
 #     1  31     days = [d for d in range(1, 32)] #      weeks = [days[i:i+7] for i in range(0, len(days), 7)] print(weeks) # [[1, 2, 3, 4, 5, 6, 7], [8, 9, 10, 11, 12, 13, 14], [15, 16, 17, 18, 19, 20, 21], [22, 23, 24, 25, 26, 27, 28], [29, 30, 31]] #       5  ,   work_weeks = [week[0:5] for week in weeks] print(work_weeks) # [[1, 2, 3, 4, 5], [8, 9, 10, 11, 12], [15, 16, 17, 18, 19], [22, 23, 24, 25, 26], [29, 30, 31]] #      -   wdays = [item for sublist in work_weeks for item in sublist] print(wdays) # [1, 2, 3, 4, 5, 8, 9, 10, 11, 12, 15, 16, 17, 18, 19, 22, 23, 24, 25, 26, 29, 30, 31]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
            ,    
       #     1  31     days = [d for d in range(1, 32)] wdays6 = [wd for (i, wd) in enumerate(days, 1) if i % 7 != 0] #   7-  #   6      : wdays5 = [wd for (i, wd) in enumerate(wdays6, 1) if i % 6 != 0] print(wdays5) # [1, 2, 3, 4, 5, 8, 9, 10, 11, 12, 15, 16, 17, 18, 19, 22, 23, 24, 25, 26, 29, 30, 31] #  ,        if  , #   ,  12-    6,      2  ! #     @sophist: days = [d + 1 for d in range(31) if d % 7 < 5]
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     10. 2.
-             
      
:
      
 -             ,    ,          SQL   Excel . 
      
:squared_evens = [n ** 2 # SELECT for n in numbers # FROM if n % 2 == 0] # WHERE
 -  UPD  fireSparrow :   Python — PythonQL,         . 
      
 -     ,       . 
      
 -           (  ). 
      
 
| パート1 | パート2 | パート3 | 4 | 
|---|
ディスカッションに招待します。
- 私がどこかで間違えたか、重要なことを考慮しなかった場合-コメントを書いてください。重要なコメントは、著者名を示す記事の後半に追加されます。
 - 明確でない点があり、説明が必要な場合は、コメントに質問を書いてください。または、私または他の読者が答えを出すと、答えのある実用的な質問が後で記事に追加されます。