2009-08-22 11 views
6

Mam tablicę 3D w Pythonie i potrzebuję iteracji nad wszystkimi sześcianami w tablicy. Oznacza to, że dla wszystkich (x,y,z) w wymiarach tablicowych muszę dostęp kostkę:Pythonowy sposób iterowania na macierzy 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)] 

tablica jest tablicą Numpy, choć nie jest to naprawdę konieczne. Po prostu bardzo łatwo było odczytać dane za pomocą jednej linijki przy użyciu numpy.fromfile().

Czy istnieje więcej Pythonic sposób iteracji nad tymi niż następujące? To po prostu wygląda jak C używając składni Pythona.

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

zostanie to odebrane przez http : //stackoverflow.com/questions/1280667/in-python-is-there-an-easier-way-to-write-6-nested-for-loops? – tom10

+0

To byłby zakres (...- 1), tutaj ... – EOL

+0

Właściwie tak @ tom10, to odpowiada na pytanie –

Odpowiedz

14

spojrzeć itertools, zwłaszcza itertools.product. można skompresować trzy pętle w jednym z

import itertools 

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

Można również utworzyć sześcian ten sposób:

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

i dodać offsetu przez proste dodanie

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

które do przetłumaczyć na cube + (x,y,z) w twoim przypadku. Bardzo zwarta wersja kodu byłoby

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 sprawia, że ​​produkt na różnych argumentów, tj itertools.product(a,b,c), więc muszę zdać map(xrange, ...) z jak *map(...)

+0

Powoduje to błąd: ValueError: niedopasowanie kształtu: obiekty nie mogą być transmitowane do pojedynczego kształtu –

+0

... Jednak używając '(x, y, z)' zamiast 'offset' w przykładowych poprawkach, które –

+0

\ * westchnienie * zawsze przetestuj swój kod przed jego wstawieniem –

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]) 
Powiązane problemy