In python is there an easier way to write 6 nested for loops?

给你一囗甜甜゛ 提交于 2019-11-28 04:20:44

If you're frequently iterating over a Cartesian product like in your example, you might want to investigate Python 2.6's itertools.product -- or write your own if you're in an earlier 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()

This is fairly common when looping over multidimensional spaces. My solution is:

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

When faced with that sort of program logic, I would probably break up the sequence of loops into two or more separate functions.

Another technique in Python is to use list comprehensions where possible, instead of a loop.

Assuming each loop has some sort of independent meaning, break them out into named functions:

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.

I could perhaps have chosen better names. 8-)

Technically, you could use itertools.product to get a cartesian product of N sequences, and iterate over that:

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

But I don't think that actually wins you anything readability-wise.

Python iterators, and generators in particular, exist exactly to allow the nice refactoring of otherwise-complicated loops. Of course, it's hard to get an abstraction out from a simple example, but assuming the 3 needs to be a parameter (maybe the whole range(3) should be?), and the two functions you're calling need some parameters that are loop variables, you could refactor the code:

  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)

into, e.g.:

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:])

The exact kind of refactoring will no doubt need to be tweaked for your exact purposes, but the general point that iterators (and usually in fact just simple generators) afford very nice refactorings of loops remains -- all the looping logic goes inside the generator, and the application-level code is left with simple for loops and actual application-relevant processing of the items yielded in the for loops.

My personal argument would be that you're likely doing something wrong if you have 6 nested loops...

That said, functional decomposition is what you're looking for. Refactor so some of the loops happen in seperate function calls, then call those functions.

From your code it looks like you want to perform an operation with every possible pair of points where x and y are in the range 0..2.

To do that:

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

The operation do_something_with_two_points will be called 81 times - once for every possible combination of points.

Have you looked into List Comprehensions?

Something like:

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

That way looks pretty straightforward and easy. Are you are saying you want to generalize to multiple layers of loops.... can you give a real-life example?

Another option I could think of would be to use a function to generate the parameters and then just apply them in a loop

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

for x,y in generate_params(3):
    do_something()

you can also use the map() function

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!