对于多维范围,是否有Python等效范围(n)?

时间:2012-04-10 17:15:35

标签: python numpy iteration range

在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或它的标准/公共库上有内置函数。

7 个答案:

答案 0 :(得分:60)

在numpy中,它是numpy.ndindex。另请查看numpy.ndenumerate

E.g。

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 :(得分:36)

您可以使用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是一个非常棒的模块。同样,regexp比“普通”字符串方法更具表现力,itertools是表达复杂循环的一种非常优雅的方式。 You owe it to yourself to read the itertools module documentation.它会让你的生活变得更有趣。

答案 2 :(得分:22)

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

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

答案 3 :(得分:6)

因此,这是两个列表中的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)

答案 4 :(得分:3)

您可以使用product模块中的itertools

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

答案 5 :(得分:3)

我会看看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)]

答案 6 :(得分:1)

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)