迭代 3D 数组的 Pythonic 方式
Posted
技术标签:
【中文标题】迭代 3D 数组的 Pythonic 方式【英文标题】:Pythonic way of iterating over 3D array 【发布时间】:2010-11-21 21:52:35 【问题描述】:我在 Python 中有一个 3D 数组,我需要遍历数组中的所有立方体。也就是说,对于数组维度中的所有(x,y,z)
,我需要访问多维数据集:
array[(x + 0, y + 0, z + 0)]
array[(x + 1, y + 0, z + 0)]
array[(x + 0, y + 1, z + 0)]
array[(x + 1, y + 1, z + 0)]
array[(x + 0, y + 0, z + 1)]
array[(x + 1, y + 0, z + 1)]
array[(x + 0, y + 1, z + 1)]
array[(x + 1, y + 1, z + 1)]
该数组是一个 Numpy 数组,尽管这并不是必需的。我刚刚发现使用numpy.fromfile()
使用单行代码读取数据非常容易。
有没有比以下更 Pythonic 的方式来迭代这些?这看起来就像使用 Python 语法的 C。
for x in range(x_dimension):
for y in range(y_dimension):
for z in range(z_dimension):
work_with_cube(array[(x + 0, y + 0, z + 0)],
array[(x + 1, y + 0, z + 0)],
array[(x + 0, y + 1, z + 0)],
array[(x + 1, y + 1, z + 0)],
array[(x + 0, y + 0, z + 1)],
array[(x + 1, y + 0, z + 1)],
array[(x + 0, y + 1, z + 1)],
array[(x + 1, y + 1, z + 1)])
【问题讨论】:
***.com/questions/1280667/… 会回答这个问题吗? 那将是范围(...-1),这里... 实际上,是的@tom10,它确实回答了这个问题 【参考方案1】:看看itertools,尤其是itertools.product。您可以使用
将三个循环压缩为一个import itertools
for x, y, z in itertools.product(*map(xrange, (x_dim, y_dim, z_dim)):
...
您也可以这样创建立方体:
cube = numpy.array(list(itertools.product((0,1), (0,1), (0,1))))
print cube
array([[0, 0, 0],
[0, 0, 1],
[0, 1, 0],
[0, 1, 1],
[1, 0, 0],
[1, 0, 1],
[1, 1, 0],
[1, 1, 1]])
并通过简单的加法来添加偏移量
print cube + (10,100,1000)
array([[ 10, 100, 1000],
[ 10, 100, 1001],
[ 10, 101, 1000],
[ 10, 101, 1001],
[ 11, 100, 1000],
[ 11, 100, 1001],
[ 11, 101, 1000],
[ 11, 101, 1001]])
在您的情况下将转换为cube + (x,y,z)
。您的代码的非常紧凑的版本是
import itertools, numpy
cube = numpy.array(list(itertools.product((0,1), (0,1), (0,1))))
x_dim = y_dim = z_dim = 10
for offset in itertools.product(*map(xrange, (x_dim, y_dim, z_dim))):
work_with_cube(cube+offset)
编辑:itertools.product
通过不同的参数生成产品,即itertools.product(a,b,c)
,所以我必须将map(xrange, ...)
传递为*map(...)
【讨论】:
这会导致错误:ValueError: shape mismatch: objects cannot be broadcast to a single shape ...但是,在您的示例中使用(x,y,z)
而不是 offset
可以解决此问题
*map(...)
中的*
有什么作用?
@Nathan:它使用列表作为参数调用函数。 s=[1,2,3]; foo(*s)
与 foo(1,2,3)
相同
与foo(s)
不同,foo
只传递一个参数,列表s
?【参考方案2】:
import itertools
for x, y, z in itertools.product(xrange(x_size),
xrange(y_size),
xrange(z_size)):
work_with_cube(array[x, y, z])
【讨论】:
以上是关于迭代 3D 数组的 Pythonic 方式的主要内容,如果未能解决你的问题,请参考以下文章
只要基于前一个元素的条件为真,“Pythonic”方式就可以从可迭代对象中返回元素