numpy 对于多维范围,是否有与range(n)等价的Python?

xiozqbni  于 2023-08-05  发布在  Python
关注(0)|答案(7)|浏览(98)

在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或其标准/通用库上是否有内置函数。

jdgnovmf

jdgnovmf1#

在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

mxg2im7a

mxg2im7a2#

可以使用itertools.product()

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

字符串
如果你想把它扩展到一个10维的循环或类似的荒谬的东西,那么多个重复的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.它会让你的生活更有趣。

wj8zmpe1

wj8zmpe13#

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

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

字符串

mrwjdhj3

mrwjdhj34#

这是两个列表的笛卡尔乘积,因此:

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)

g6ll5ycj

g6ll5ycj5#

您可以从itertools模块使用product

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

字符串

uyto3xhc

uyto3xhc6#

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

ekqde3dh

ekqde3dh7#

ndindex()不是range()的ND等价物

(尽管这里有一些其他的答案)。
它适用于您的简单示例,但不允许使用任意startstopstep参数。它只接受stop,并将start硬编码为(0,0,...),将step硬编码为(1,1,...)
下面是一个更像内置range()函数的实现。也就是说,它允许任意start/stop/step参数,但它适用于 * 元组 * 而不仅仅是整数。像内置的range()一样,它返回一个可迭代对象。

from itertools import product

def ndrange(start, stop=None, step=None):
    if stop is None:
        stop = start
        start = (0,) * len(stop)
    if step is None:
        step = (1,) * len(start)

    assert len(start) == len(stop) == len(step)    
    for index in product(*map(range, 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)

numpy用户

如果您的代码是基于numpy的,那么直接使用ndarray对象可能比使用元组的可迭代对象更方便。它也可能更快。如果您计划将结果转换为ndarray*,则以下实现比使用上述 * 更快。

def ndrange_array(start, stop=None, step=None):
    """
    Like np.ndindex, but accepts start/stop/step instead of
    assuming that start is always (0,0,0) and step is (1,1,1),
    and returns an array instead of an iterator.
    """
    start = np.asarray(start)
    if stop is None:
        stop = start
        start = (0,) * len(stop)
    if step is None:
        step = 1

    def ndindex(shape):
        """Like np.ndindex, but returns ndarray"""
        return np.indices(shape).reshape(len(shape), -1).transpose()

    shape = (stop - start + step - 1) // step
    return start + step * ndindex(shape)

相关问题