Питонический способ итерации по трехмерному массиву - PullRequest
6 голосов
/ 22 августа 2009

У меня есть 3D-массив в Python, и мне нужно перебрать все кубы в массиве. То есть для всех (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 способ перебрать их, чем следующий? Это просто выглядит как C с использованием синтаксиса Python.

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)])

Ответы [ 2 ]

17 голосов
/ 22 августа 2009

Посмотрите на 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(...)

8 голосов
/ 22 августа 2009
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])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...