【问题标题】:In python is there an easier way to write 6 nested for loops?在 python 中是否有更简单的方法来编写 6 个嵌套的 for 循环?
【发布时间】:2010-11-19 19:43:30
【问题描述】:

这个问题已经困扰我一段时间了。有没有更简单的方法在 python 中编写嵌套的for 循环?例如,如果我的代码是这样的:

  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 个空格时,它可能会成为一个问题。

哦,在示例中,只有 4 个嵌套的 for 循环使事情变得更容易。

【问题讨论】:

标签: python for-loop nested-loops


【解决方案1】:

如果您像示例中那样经常迭代笛卡尔积,您可能需要调查Python 2.6's 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()

【讨论】:

  • 如果嵌套循环是这样的:for y in range(3): do_something1() for x in range(3): do_something()我该如何使用产品
  • @ErtuğrulAltınboğa 如果没有缩进,就不可能知道你想做什么。我建议提出一个新的 StackOverflow 问题,而不是尝试在 cmets 中寻求帮助。
【解决方案2】:

这在循环多维空间时相当常见。我的解决方案是:

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

【讨论】:

  • 另外,如果您有大量元素要循环,最好使用生成器表达式,即xy_grid = ((x,y) for x in range(30000) for y in range(30000))
【解决方案3】:

当面对这种程序逻辑时,我可能会将循环序列分解为两个或多个单独的函数。

Python 中的另一种技术是尽可能使用list comprehensions,而不是循环。

【讨论】:

    【解决方案4】:

    假设每个循环都有某种独立的含义,将它们分解为命名函数:

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

    【讨论】:

    • 如果我是狮子,我会做母狮。
    • 嗯,这是养小猫的一种方法……不过,比我想象的要大一些。
    【解决方案5】:

    从技术上讲,您可以使用 itertools.product 获得 N 个序列的笛卡尔积,然后对其进行迭代:

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

    但我认为这实际上不会为您赢得任何可读性。

    【讨论】:

      【解决方案6】:

      Python 迭代器,尤其是生成器,正是为了对原本复杂的循环进行良好的重构而存在。当然,很难从一个简单的例子中得到一个抽象,但是假设3 需要是一个参数(也许整个range(3) 应该是?),并且你调用的两个函数需要一些参数是循环变量,你可以重构代码:

        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 循环中产生的项目的实际应用程序相关处理。

      【讨论】:

        【解决方案7】:

        我个人的观点是,如果你有 6 个嵌套循环,你可能做错了什么......

        也就是说,功能分解正是您要寻找的。重构一些循环在单独的函数调用中发生,然后调用这些函数。

        【讨论】:

        • 这是我上次有这么多嵌套循环的用例:想象将 3D 高斯“模糊”过滤器应用于 3D 数据集;您已经获得了过滤器的所有三个方向的总和(3 个循环),并在三个方向上迭代每个点以应用它(另外 3 个循环)。哦,我过滤的数据是速度,所以要迭代三个组件(最后一个循环)。
        【解决方案8】:

        从您的代码看来,您希望对 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 次 - 每个可能的点组合调用一次。

        【讨论】:

          【解决方案9】:

          你看过List Comprehensions?

          类似:

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

          【讨论】:

            【解决方案10】:

            这种方式看起来非常简单明了。你是说你想推广到多层循环......你能举一个真实的例子吗?

            我能想到的另一个选择是使用函数来生成参数,然后在循环中应用它们

            def generate_params(n):
                return itertools.product(range(n), range(n))
            
            for x,y in generate_params(3):
                do_something()
            

            【讨论】:

              【解决方案11】:

              你也可以使用map()function

              【讨论】:

                猜你喜欢
                • 2022-01-10
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多