【问题标题】:Pythonic way of iterating over 3D array迭代 3D 数组的 Pythonic 方式
【发布时间】: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)])

【问题讨论】:

标签: python arrays loops


【解决方案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])

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-08-18
    • 2011-04-19
    • 1970-01-01
    • 2021-03-07
    • 2018-11-28
    • 2018-03-17
    • 2017-12-16
    • 2016-11-17
    相关资源
    最近更新 更多