I have a 3D array in Python and I need to iterate over all the cubes in the array. That is, for all (x,y,z)
in the array's dimensions I need to access the 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)]
The array is a Numpy array, though that's not really necessary. I just found it very easy to read the data in with a one-liner using numpy.fromfile()
.
Is there any more Pythonic way to iterate over these than the following? That simply looks like C using Python syntax.
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)])
In order to loop over a 2D array, we first go through each row, and then again we go through each column in every row. That's why we need two loops, nested in each other. Anytime, if you want to come out of the nested loop, you can use the break statement.
NumPy package contains an iterator object numpy. It is an efficient multidimensional iterator object using which it is possible to iterate over an array. Each element of an array is visited using Python's standard Iterator interface.
Have a look at itertools, especially itertools.product. You can compress the three loops into one with
import itertools
for x, y, z in itertools.product(*map(xrange, (x_dim, y_dim, z_dim)):
...
You can also create the cube this way:
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]])
and add the offsets by a simple addition
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]])
which would to translate to cube + (x,y,z)
in your case. The very compact version of your code would be
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)
Edit: itertools.product
makes the product over the different arguments, i.e. itertools.product(a,b,c)
, so I have to pass map(xrange, ...)
with as *map(...)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With