2009-08-22 5 views
6

J'ai un tableau 3D en Python et j'ai besoin de parcourir tous les cubes du tableau. C'est, pour tous (x,y,z) dans les dimensions du tableau I ont besoin d'accéder au cube:Python d'itération sur un tableau 3D

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

Le tableau est un tableau numpy, bien que ce n'est pas vraiment nécessaire. Je l'ai trouvé très facile à lire les données avec un one-liner en utilisant numpy.fromfile().

Existe-t-il un moyen plus pythonique d'itérer sur ces éléments que les suivants? Cela ressemble simplement à C en utilisant la syntaxe 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)]) 
+0

aura-t-il être répondu par http : //stackoverflow.com/questions/1280667/in-python-is-there-an-easier-way-to-write-6-nested-for-loops? – tom10

+0

Ce serait la gamme (...- 1), ici ... – EOL

+0

En fait, oui @ tom10, il répond à la question –

Répondre

14

Jetez un oeil à itertools, en particulier itertools.product. Vous pouvez compresser les trois boucles en un seul avec

import itertools 

for x, y, z in itertools.product(*map(xrange, (x_dim, y_dim, z_dim)): 
    ... 

Vous pouvez également créer le cube de cette façon:

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

et ajouter les décalages par une 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]]) 

qui serait à traduire à cube + (x,y,z) dans votre cas. La version très compacte de votre code serait

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) 

Modifier: itertools.product rend le produit sur les différents arguments, à savoir itertools.product(a,b,c), donc je dois passer map(xrange, ...) avec comme *map(...)

+0

Il en résulte l'erreur: ValueError: discordance de forme: les objets ne peuvent pas être diffusés en une seule forme –

+0

... Cependant, en utilisant '(x, y, z)' au lieu de 'offset' dans votre exemple, –

+0

\ * sigh * vérifie toujours votre code avant de l'afficher –

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