web-dev-qa-db-ja.com

Forループのネストされた単一行

行列を転置するpythonでこの関数を書きました:

def transpose(m):
    height = len(m)
    width = len(m[0])
    return [ [ m[i][j] for i in range(0, height) ] for j in range(0, width) ]

その過程で、forループがネストされた単一行の実行方法を完全に理解していないことに気付きました。次の質問に答えて、理解を助けてください。

  1. このforループが実行される順序は何ですか?
  2. トリプルネストされたforループがある場合、どの順序で実行されますか?
  3. ループの入れ子になっていないforループと等しいもの

与えられた、

[ function(i,j) for i,j in object ]
  1. これをループ構造に使用するには、どのタイプのオブジェクトが必要ですか?
  2. Iとjがオブジェクトの要素に割り当てられる順序は何ですか?
  3. 別のforループ構造でシミュレートできますか?
  4. これをforループは、類似または異なるforループ構造でネストできますか?そして、それはどのように見えるでしょうか?

追加情報も歓迎します。

81
Asher Garland

最良の情報源は リスト内包表記の公式Pythonチュートリアル です。リスト内包表記はforループとほぼ同じですが(リスト内包表記はすべてforループとして記述できます)、forループを使用するよりも高速です。

チュートリアルのこの長いリスト内包表記を見てください(if部分が内包表記をフィルタリングします。ifステートメントを渡す部分のみがリスト内包表記の最後の部分(ここでは(x,y))に渡されます:

>>> [(x, y) for x in [1,2,3] for y in [3,1,4] if x != y]
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]

これはネストされたforループとまったく同じです(チュートリアルで述べているように、forとifの順序が同じであることに注意してください)。

>>> combs = []
>>> for x in [1,2,3]:
...     for y in [3,1,4]:
...         if x != y:
...             combs.append((x, y))
...
>>> combs
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]

リスト内包表記とforループの主要なdifferenceは、forループの最後の部分(何かを行う場所)が最初ではなく最後に。

あなたの質問に:

これをループ構造に使用するには、どのタイプのオブジェクトが必要ですか?

反復可能 。 (有限の)要素のセットを生成できるオブジェクト。これらには、コンテナ、リスト、セット、ジェネレータなどが含まれます。

Iとjがオブジェクトの要素に割り当てられる順序は何ですか?

ネストされたforループ内にあるかのように、各リストから生成される順序とまったく同じ順序で割り当てられます(最初の理解では、iに対して1つの要素を取得し、jからのすべての値、2番目の要素からi、その後、jからのすべての値など)

別のforループ構造でシミュレートできますか?

はい、すでに上に示しました。

これをforループは、類似または異なるforループ構造でネストできますか?そして、それはどのように見えるでしょうか?

確かに、それは素晴らしいアイデアではありません。ここでは、たとえば、文字のリストのリストを提供します:

[[ch for ch in Word] for Word in ("Apple", "banana", "pear", "the", "hello")]
134
Jeff Tratner

itertools.product に興味があるかもしれません。これは、渡したすべての反復可能オブジェクトから値のタプルを生成する反復可能オブジェクトを返します。つまり、itertools.product(A, B)(a, b)という形式のすべての値を生成します。ここで、aの値はAから、bの値はBから取得されます。例えば:

import itertools

A = [50, 60, 70]
B = [0.1, 0.2, 0.3, 0.4]

print [a + b for a, b in itertools.product(A, B)]

これは印刷します:

[50.1, 50.2, 50.3, 50.4, 60.1, 60.2, 60.3, 60.4, 70.1, 70.2, 70.3, 70.4]

itertools.productに渡される最後の引数が「内部」引数であることに注意してください。一般的に、itertools.product(a0, a1, ... an)[(i0, i1, ... in) for in in an for in-1 in an-1 ... for i0 in a0]と等しい

25
Lynn

まず、最初のコードはforループ自体を使用せず、 リスト内包表記 を使用します。

  1. と同等になります

    範囲jの場合(0、幅):範囲iの場合(0、高さ):m [i] [j]

  2. ほぼ同じ方法で、一般的にforループのように右から左にネストします。しかし、リスト内包構文はより複雑です。

  3. この質問が何を尋ねているのか分かりません


  1. 正確に2つのオブジェクトを生成する反復可能なオブジェクトを生成する反復可能なオブジェクト(一口-つまり[(1,2),'ab']が有効です)

  2. 反復時にオブジェクトが生成される順序。 iは最初のyield、jは2番目のyieldになります。

  3. はい、しかしそれほどきれいではありません。私はそれが機能的に同等であると信じています:

     l = list()
     for i、j for object:
     l.append(function(i、j))
    

    または map

    map(function, object)
    

    ただし、もちろん関数はij自体を取得する必要があります。

  4. これは3と同じ質問ではありませんか?

2
korylprince