【问题标题】:Is there a Python equivalent of range(n) for multidimensional ranges?对于多维范围,是否有 Python 的 range(n) 等价物?
【发布时间】:2023-04-09 13:41:01
【问题描述】:

在 Python 上,range(3) 将返回 [0,1,2]。多维范围是否有等价物?

range((3,2)) # [(0,0),(0,1),(1,0),(1,1),(2,0),(2,1)]

因此,例如,在基于图块的游戏中循环通过矩形区域的图块可以写成:

for x,y in range((3,2)):

请注意,我不是要求实现。我想知道这是否是一种公认​​的模式,以及 Python 上是否有内置函数或其标准/通用库。

【问题讨论】:

    标签: python numpy iteration range


    【解决方案1】:

    实际上有一个简单的语法。你只需要两个fors:

    >>> [(x,y) for x in range(3) for y in range(2)]
    [(0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1)]
    

    【讨论】:

    • 这很好,但我想指出它可能有点冗长: for (x,y) in [(x,y) for x in range(3) for y in range (2)]:
    【解决方案2】:

    你可以使用itertools.product():

    >>> import itertools
    >>> for (i,j,k) in itertools.product(xrange(3),xrange(3),xrange(3)):
    ...     print i,j,k
    

    多个重复的xrange() 语句可以这样表达,如果你想把它放大到一个十维循环或类似的荒谬的东西:

    >>> for combination in itertools.product( xrange(3), repeat=10 ):
    ...     print combination
    

    其中循环了十个变量,从 (0,0,0,0,0,0,0,0,0,0)(2,2,2,2,2,2,2,2,2,2)


    总的来说,itertools 是一个非常棒的模块。同样,正则表达式比“普通”字符串方法更具表现力,itertools 是表达复杂循环的一种非常优雅的方式。 You owe it to yourself to read the itertools module documentation.它会让你的生活更有趣。

    【讨论】:

    • 只是比您上一个答案的微小改进:for c in product(*([xrange(5)]*3)): print c:从 (0,0,0) 到 (4,4,4)
    • 如果你想要精确的副本,实际上最好使用itertools.tee() - 我相信由于缓存,底层实现更有效。
    • @agf:很好的收获——显然是时候让我睡觉了。为此进行了编辑。
    【解决方案3】:

    您可以使用来自itertools 模块的product

    itertools.product(range(3), range(2))
    

    【讨论】:

      【解决方案4】:

      这是两个列表中的cartesian product,因此:

      import itertools
      for element in itertools.product(range(3),range(2)):
          print element
      

      给出这个输出:

      (0, 0)
      (0, 1)
      (1, 0)
      (1, 1)
      (2, 0)
      (2, 1)
      

      【讨论】:

        【解决方案5】:

        我会看看numpy.meshgrid

        http://docs.scipy.org/doc/numpy-1.6.0/reference/generated/numpy.meshgrid.html

        这将为您提供网格/网格中每个位置的 X 和 Y 网格值。然后你可以这样做:

        import numpy as np
        X,Y = np.meshgrid(xrange(3),xrange(2))
        zip(X.ravel(),Y.ravel()) 
        #[(0, 0), (1, 0), (2, 0), (0, 1), (1, 1), (2, 1)]
        

        zip(X.ravel(order='F'),Y.ravel(order='F')) 
        # [(0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1)]
        

        【讨论】:

        • 最好在此处提及numpy.mgridnumpy.ogrid
        【解决方案6】:

        在 numpy 中,它是 numpy.ndindex。也可以看看numpy.ndenumerate

        例如

        import numpy as np
        for x, y in np.ndindex((3,2)):
            print(x, y)
        

        这会产生:

        0 0
        0 1
        1 0
        1 1
        2 0
        2 1
        

        【讨论】:

        • +1:其语法与 OP 最初要求的惊人地相似。打得好!
        • 正如 Li-aung 所指出的,这与我所要求的惊人地相似,所以毫无疑问,这是该主题的最佳答案。
        • Li-aung Yip 的回答也很棒,并且有一些学习,因为它表明笛卡尔积可以用于相同的目的。
        • 这使得 Numpy 数组的负载变得更加通用,功能强大。
        【解决方案7】:

        Numpy 的 ndindex() 适用于您给出的示例,但它并不适用于所有用例。与 Python 的内置 range() 不同,后者允许任意 startstopstep,numpy 的 np.ndindex() 只接受 stop。 (start 假定为(0,0,...)step(1,1,...)。)

        这是一个更像内置 range() 函数的实现。也就是说,它允许任意 start/stop/step 参数,但它适用于 元组 而不仅仅是整数。

        import sys
        from itertools import product, starmap
        
        # Python 2/3 compatibility
        if sys.version_info.major < 3:
            from itertools import izip
        else:
            izip = zip
            xrange = range
        
        def ndrange(start, stop=None, step=None):
            if stop is None:
                stop = start
                start = (0,)*len(stop)
        
            if step is None:
                step = (1,)*len(stop)
        
            assert len(start) == len(stop) == len(step)
        
            for index in product(*starmap(xrange, izip(start, stop, step))):
                yield index
        

        例子:

        In [7]: for index in ndrange((1,2,3), (10,20,30), step=(5,10,15)):
           ...:     print(index)
           ...:
        (1, 2, 3)
        (1, 2, 18)
        (1, 12, 3)
        (1, 12, 18)
        (6, 2, 3)
        (6, 2, 18)
        (6, 12, 3)
        (6, 12, 18)
        

        【讨论】:

        • 正好赶上冲刺!​​
        猜你喜欢
        • 1970-01-01
        • 2021-03-29
        • 2012-07-17
        • 2012-06-14
        • 1970-01-01
        • 2014-01-09
        • 1970-01-01
        • 1970-01-01
        • 2017-12-17
        相关资源
        最近更新 更多