2012-04-10 29 views
40

W języku Python zakres (3) zwróci [0,1,2]. Czy istnieje odpowiednik dla zakresów wielowymiarowych?Czy istnieje odpowiednik w języku Python dla zakresu (n) dla zakresów wielowymiarowych?

range((3,2)) # [(0,0),(0,1),(1,0),(1,1),(2,0),(2,1)] 

Tak więc, na przykład, zapętlenie choć płytki prostokątnego obszaru na grze opartej płytek można zapisać jako:

for x,y in range((3,2)): 

Uwaga Nie pytam dla implementacji. Chciałbym wiedzieć, czy jest to uznany wzorzec i czy jest wbudowana funkcja w Pythonie lub jego standardowych/wspólnych bibliotekach.

Odpowiedz

50

W numpy, to numpy.ndindex. Zobacz także numpy.ndenumerate.

E.g.

import numpy as np 
for x, y in np.ndindex((3,2)): 
    print x, y 

Daje:

0 0 
0 1 
1 0 
1 1 
2 0 
2 1 
+4

+1: Składnia tego jest alarmująco podobna do tego, o co pierwotnie prosił OP. Dobrze rozegrane! –

+0

Jak wskazał Li-aung, jest to alarmująco podobne do tego, o co prosiłem, więc jest to niewątpliwie najlepsza odpowiedź na ten temat. – MaiaVictor

+1

Odpowiedź Li-aung Yip jest również świetna i ma pewną wiedzę na ten temat, ponieważ pokazuje, że produkt kartezjański może być używany do tego samego celu. – MaiaVictor

22

Istnieje w rzeczywistości prosta składnia. Trzeba tylko mieć dwa for s:

>>> [(x,y) for x in range(3) for y in range(2)] 
[(0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1)] 
+0

to dobrze, ale I przypomnieć, że może się nieco skróconej: dla (x, y) w [(x, y) dla xw zakres (3) dla y w zakresie (2)]: – MaiaVictor

35

Można użyć itertools.product():

>>> import itertools 
>>> for (i,j,k) in itertools.product(xrange(3),xrange(3),xrange(3)): 
...  print i,j,k 

Wielokrotne powtarzane xrange() oświadczenia można wyrazić jak więc, jeśli chcesz przeskalować to do dziesięcioletniego pętla wymiarowej lub coś podobnie absurdalne:

>>> for combination in itertools.product(xrange(3), repeat=10): 
...  print combination 

które pętle ponad dziesięciu zmiennych, począwszy od (0,0,0,0,0,0,0,0,0,0) do (2,2,2,2,2,2,2,2,2,2).


Ogólnie rzecz biorąc itertools to niesamowicie niesamowity moduł. W ten sam sposób regexps są znacznie bardziej ekspresywne niż "zwykłe" metody łańcuchowe, itertools to bardzo elegancki sposób wyrażania złożonych pętli. You owe it to yourself to read the itertools module documentation. Sprawi, że Twoje życie będzie bardziej zabawne.

+0

tylko niewielka poprawa w porównaniu z ostatnią odpowiedzią: 'dla cw produkcie (* ([xrange (5)] * 3)): print c': from (0 , 0,0) do (4,4,4) – egor83

+0

Właściwie lepiej jest użyć 'itertools.tee()' jeśli chcesz dokładnych replik - uważam, że podstawowa implementacja jest bardziej wydajna z powodu buforowania. –

+0

@ egor83/Li-aung Yip: Proszę zapoznać się z dokumentacją 'itertools' przed zaproponowaniem skomplikowanych rozwiązań. To jest 'itertools.product (xrange (3), repeat = 3)'. – agf

3

Można użyć product z modułu itertools.

itertools.product(range(3), range(2)) 
6

To cartesian product dwóch listach Dlatego:

import itertools 
for element in itertools.product(range(3),range(2)): 
    print element 

daje to wyjście:

(0, 0) 
(0, 1) 
(1, 0) 
(1, 1) 
(2, 0) 
(2, 1) 
3

chciałbym spojrzeć na numpy.meshgrid:

http://docs.scipy.org/doc/numpy-1.6.0/reference/generated/numpy.meshgrid.html

, który da wartości siatki X i Y w każdej pozycji w siatce/siatce. Następnie można zrobić coś takiego:

import numpy as np 
X,Y = np.meshgrid(xrange(3),xrange(2)) 
zip(X.ravel(),Y.ravel()) 
#[(0, 0), (1, 0), (2, 0), (0, 1), (1, 1), (2, 1)] 

lub

zip(X.ravel(order='F'),Y.ravel(order='F')) 
# [(0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1)] 
+0

dobrze byłoby również wspomnieć o 'numpy.mgrid' i' numpy.ogrid' tutaj. –

1

NumPy za ndindex() pracuje dla przykładu dałeś, ale nie służą wszystkie przypadki użycia. W przeciwieństwie do wbudowanego w Python range(), który zezwala zarówno na dowolne, jak i na,, stop i , numpy's np.ndindex() akceptuje tylko stop. (The start jest uznawany (0,0,...) i step jest (1,1,...).)

Oto implementacja który działa bardziej jak wbudowany range() funkcji. Oznacza to, że zezwala na arbitralne argumenty, ale działa na krotek zamiast zwykłych liczb całkowitych.

import sys 
from itertools import product, starmap 

# Python 2/3 compatibility 
if sys.version_info.major < 3: 
    from itertools import izip 
else: 
    izip = zip 
    xrange = range 

def ndrange(start, stop=None, step=None): 
    if stop is None: 
     stop = start 
     start = (0,)*len(stop) 

    if step is None: 
     step = (1,)*len(stop) 

    assert len(start) == len(stop) == len(step) 

    for index in product(*starmap(xrange, izip(start, stop, step))): 
     yield index 

przykład:

In [7]: for index in ndrange((1,2,3), (10,20,30), step=(5,10,15)): 
    ...:  print(index) 
    ...: 
(1, 2, 3) 
(1, 2, 18) 
(1, 12, 3) 
(1, 12, 18) 
(6, 2, 3) 
(6, 2, 18) 
(6, 12, 3) 
(6, 12, 18) 
+0

W samą porę na sprint! – MaiaVictor

Powiązane problemy