web-dev-qa-db-ja.com

pythonに、ネストされたforループを6つ記述する簡単な方法はありますか?

この問題はしばらく前から私に起こりました。ネストされたforループをPythonで書く簡単な方法はありますか?たとえば、私のコードが次のようになった場合:

  for y in range(3):
    for x in range(3):
      do_something()
      for y1 in range(3):
        for x1 in range(3):
          do_something_else()

これを行う簡単な方法はありますか?私はこのコードが機能することを知っていますが、私のように2つのスペースを使用する代わりにインデントすると、問題になる可能性があります。

例では、物事を簡単にするために、ネストされたforループは4つしかありませんでした。

38
saleh

例のようにデカルト積を頻繁に反復している場合は、 Python 2.6のitertools.product -を調査するか、以前のPythonを使用している場合は独自に作成することをお勧めします。

from itertools import product
for y, x in product(range(3), repeat=2):
  do_something()
  for y1, x1 in product(range(3), repeat=2):
    do_something_else()
58
Alice Purcell

これは、多次元空間をループする場合にかなり一般的です。私の解決策は:

xy_grid = [(x, y) for x in range(3) for y in range(3)]

for x, y in xy_grid:
    # do something
    for x1, y1 in xy_grid:
        # do something else
14
tom10

この種のプログラムロジックに直面したとき、ループのシーケンスを2つ以上の個別の関数に分割するでしょう。

Python=のもう1つのテクニックは、ループの代わりに list comprehensions を使用することです。

10
Greg Hewgill

各ループに何らかの独立した意味があると仮定して、それらを名前付き関数に分割します。

def do_tigers():
    for x in range(3):
        print something

def do_lions():
    do_lionesses()
    for x in range(3):
        do_tigers()

def do_penguins():
    for x in range(3):
        do_lions()

..etc.

もっと良い名前を選んだのかもしれません。 8-)

8
RichieHindle

技術的には、itertools.product Nシーケンスのデカルト積を取得し、それを繰り返します。

 for y, x, y1, x1 in itertools.product(range(3), repeat=4):
   do_something_else()

しかし、それが実際に読みやすさの点であなたに勝つとは思いません。

5
Pavel Minaev

Pythonイテレータ、特にジェネレータは、複雑なループのニースリファクタリングを可能にするために正確に存在します。もちろん、単純な例から抽象化を引き出すことは困難ですが、_3_はパラメーターである必要があると想定して(おそらくrange(3)全体を指定する必要がありますか?)、2つの関数呼び出しには、ループ変数であるいくつかのパラメーターが必要です。コードをリファクタリングできます。

_  for y in range(3):
    for x in range(3):
      do_something(x, y)
      for y1 in range(3):
        for x1 in range(3):
          do_something_else(x, y, x1, y1)
_

例:

_def nestloop(n, *funcs):
  head = funcs[0]
  tail = funcs[1:]
  for y in range(n):
    for x in range(n):
      yield head, x, y
      if tail:
        for subtup in nestloop(n, *tail):
           yield subtup[:1] + (x, y) + subtup[1:]

for funcandargs in nestloop(3, do_something, do_something_else):
  funcandargs[0](*funcandargs[1:])
_

正確な種類のリファクタリングは、正確な目的のために微調整する必要があることは間違いありませんが、イテレータ(通常、実際には単純なジェネレータのみ)が非常に優れたループのリファクタリングを提供するという一般的な点は残ります-すべてのループロジックはジェネレータの内部に入ります。また、アプリケーションレベルのコードには、単純なforループと、forループで生成されたアイテムの実際のアプリケーション関連の処理が残されています。

4
Alex Martelli

私の個人的な議論は、6つのネストされたループがある場合、おそらく何かが間違っているということでしょう...

そうは言っても、機能分解はあなたが探しているものです。一部のループが個別の関数呼び出しで発生するようにリファクタリングしてから、それらの関数を呼び出します。

3

コードから、xとyが0..2の範囲にあるすべての可能なポイントのペアで操作を実行したいようです。

それを行うには:

for x1,y1,x2,y2 in itertools.product(range(3), repeat=4):
    do_something_with_two_points(x1,y1,2,y2)

操作 do_something_with_two_pointsは81回呼び出されます-ポイントのすべての可能な組み合わせに対して1回。

3
Triptych

リスト内包を調べましたか?

何かのようなもの:

[do_something() for x in range(3) for y in range(3)]
2
Yancy

その方法は、かなり簡単で簡単に見えます。ループの複数の層に一般化したいということですか...実際の例を挙げられますか?

私が考えることができるもう1つのオプションは、関数を使用してパラメーターを生成し、それをループに適用することです

def generate_params(n):
    return itertools.product(range(n), range(n))

for x,y in generate_params(3):
    do_something()
2
Joe Koberg

map()function を使用することもできます

2
jle