ループを入れ子にした単一行


102

行列を転置する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行がどのように実行されるのか完全に理解していないことに気付きました。次の質問に答えて理解を助けてください。

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

与えられた、

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

追加情報も歓迎します。

回答:


169

最良の情報源は、リスト内包表記に関する公式の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ループの主な違いは、forループの最後の部分(何かを行う場所)が最後ではなく最初に来るということです。

あなたの質問に:

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

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

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

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

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

はい、すでに上に表示されています。

これのforループは、forまたはloopの構造が同じか異なる入れ子にできますか?そしてそれはどのように見えますか?

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

[[ch for ch in word] for word in ("apple", "banana", "pear", "the", "hello")]

何が彼らの二重ネスティングにおける順序付けの選択を導いたのだろうか。私は他の方法がより自然であると思います(例ではyの場合はxの場合)。私は、Pythonを(広範囲にではなく、まだ...)3年行って、そのような種類のループを使用した3年後に気づきました。
トーマス

@Thomas私はまた、他の方法の方が直感的だと思っています。私が信じている選択は純粋に便利だった。より直感的な方法でそれを行うと、ステートメントの後半で検出されるまで、未解決のシンボルを処理する必要があります。紙に各都市の各city.bananastoreの各バナナの各banana.peelを解析してみてください。簡単ではありません。逆に言えば、とても簡単です。
ピジョン

29

に興味があるかもしれませんitertools.product。これは、渡したすべてのイテラブルから値のタプルを生成するイテラブルを返します。つまり、itertools.product(A, B)フォームの全ての値もたらし(a, b)a値はから来るAb値から来るの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]


4

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

  1. に相当します

    range(0、width)のjの場合:range(0、height)のiの場合:m [i] [j]

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

  3. この質問が何を求めているのかわかりません


  1. ちょうど2つのオブジェクトを生成する反復可能オブジェクトを生成する任意の反復可能オブジェクト(一口-つまり[(1,2),'ab']、有効です)

  2. 反復時にオブジェクトが生成する順序。i最初の利回り、j2番目の利回りになります。

  3. はい、しかしそれほどきれいではありません。機能的には以下と同等であると思います。

    l = list()
    オブジェクトのi、jの場合:
        l.append(関数(i、j))
    

    またはマップをよりよく使用する

    map(function, object)

    ただし、関数自体はを取得する必要がiありjます。

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


2

zip関数を使用して、同じ行で2つのforループを使用できます

コード:

list1 = ['Abbas', 'Ali', 'Usman']
list2 = ['Kamran', 'Asgar', 'Hamza', 'Umer']
list3 = []
for i,j in zip(list1,list2):
    list3.append(i)
    list3.append(j)
print(list3)

出力:

['Abbas', 'Kamran', 'Ali', 'Asgar', 'Usman', 'Hamza']

したがって、zip関数を使用すると、2つのforループを使用したり、同じ行の2つのリストを反復したりできます。


-1

2つのforループを使用しながら、ネストされたループの最良の例を以下のコードに示しますが、最初のループの出力が2番目のループの入力であることを忘れないでください。ネストされたループを使用する際のループ終了も重要

for x in range(1, 10, 1):
     for y in range(1,x):
             print y,
        print
OutPut :
1
1 2
1 2 3
1 2 3 4
1 2 3 4 5
1 2 3 4 5 6
1 2 3 4 5 6 7
1 2 3 4 5 6 7 8
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.