3

I want to loop through a three-dimensional array. Is there any alternative method which is more efficient (or faster) than the following?

for i, j, k in itertools.product(*map(xrange, (len(x), len(y), len(z))))

In this example, x, y and z are three one-dimensional arrays.

My source code is this, I do not want the value of lists.

for i, j, k in itertools.product(*map(xrange, (len(x0), len(y0), len(z0)))):
       print "p[%d][%d][%d] = %d" % (x0[i], y0[j], z0[k], p[i][j][k]) 

p being the 3d-array

JJJ
  • 32,902
  • 20
  • 89
  • 102
kshipuden
  • 93
  • 1
  • 4
  • I explain evil, edit my post, sorry – kshipuden Mar 27 '13 at 11:00
  • You do use the values of the list: `x0[i], y0[j], z0[k]` retrieves those values. – Martijn Pieters Mar 27 '13 at 11:04
  • 1
    Any time you find yourself combining `range` (or `xrange` in 2.x) and `len`, *stop* and think about what you are doing. [See also](http://stackoverflow.com/a/4383321/523612). – Karl Knechtel Mar 27 '13 at 12:12
  • You're doing nothing but printing out the values of the 3 lists, not actually using them to index the `p` array. Thus, your `print` is misleading. It would be more accurate for it to be `print "p[%d][%d][%d] = %d" % (i, j, k, p[i][j][k])`. – martineau Mar 27 '13 at 15:02

3 Answers3

6

Why not just loop over the lists themselves instead?

for i, j, k in itertools.product(x, y, z):

You do not have indices now, you have the actual values:

>>> x, y, z = range(3), range(3, 6), range(6, 9)
>>> for i, j, k in itertools.product(x, y, z):
...     print i, j, k
... 
0 3 6
0 3 7
0 3 8
0 4 6
# .. ~ ..
2 4 8
2 5 6
2 5 7
2 5 8

If you have to have the indices too, just use enumerate():

>>> for (ii, i), (jj, j), (kk, k) in itertools.product(*map(enumerate, (x, y, z))):
...     print (ii, i), (jj, j), (kk, k)
... 
(0, 0) (0, 3) (0, 6)
(0, 0) (0, 3) (1, 7)
(0, 0) (0, 3) (2, 8)
(0, 0) (1, 4) (0, 6)
# .. ~ ..
(2, 2) (1, 4) (2, 8)
(2, 2) (2, 5) (0, 6)
(2, 2) (2, 5) (1, 7)
(2, 2) (2, 5) (2, 8)
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
2

You can also do this

for i in x:
  for j in y:
    for k in z:
      print i,j,k
xuanji
  • 5,007
  • 2
  • 26
  • 35
1

You don't need the x, y, & z lists, so the following ways of looping through the array, with and without indices, are all more efficient in the sense that they don't use them:

import itertools
from pprint import pprint

W,H,D = 3,4,5
p = [[[k*W*H + j*W+i for i in xrange(3)] for j in xrange(4)] for k in xrange(5)]
assert (W,H,D) == (len(p[0][0]),len(p[0]),len(p))
pprint(p)

print
for i, j, k in itertools.product(xrange(D), xrange(H), xrange(W)):
    print "p[%d][%d][%d] = %d" % (i, j, k, p[i][j][k])
print
for i in xrange(D):
    for j in xrange(H):
        for k in xrange(W):
            print "p[%d][%d][%d] = %d" % (i, j, k, p[i][j][k])
print
for col in p:
    for row in col:
        for elem in row:
            print elem
print
for i, col in enumerate(p):
    for j, row in enumerate(col):
        for k, elem in enumerate(row):
            print "p[%d][%d][%d] = %d" % (i, j, k, elem)
martineau
  • 119,623
  • 25
  • 170
  • 301