2012-04-10 10 views
40

En Python, el rango (3) devolverá [0,1,2]. ¿Hay un equivalente para rangos multidimensionales?¿Hay un equivalente de Python de rango (n) para rangos multidimensionales?

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

Así, por ejemplo, de enlace, aunque las baldosas de un área rectangular en un juego basado en baldosas pueden ser escritas como:

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

Nota No estoy pidiendo una implementación. Me gustaría saber si este es un patrón reconocido y si hay una función incorporada en Python o sus bibliotecas estándar/comunes.

Respuesta

50

En numpy, es numpy.ndindex. También eche un vistazo a numpy.ndenumerate.

E.g.

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

Esto produce:

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

+1: La sintaxis para eso es alarmantemente similar a lo que el OP originalmente pidió. ¡Bien jugado! –

+0

Como Li-aung señaló que esto es alarmantemente similar a lo que pedí, por lo que es, sin duda, la mejor respuesta al tema. – MaiaVictor

+1

Li-aung Yip answer también es excelente y tiene algo de información, ya que muestra que el producto cartesiano se puede usar para el mismo propósito. – MaiaVictor

22

Realmente hay una sintaxis simple para esto. Usted sólo tiene que tener dos 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

Esto es bueno, pero me gustaría a punto de que puede conseguir un poco detallado: para (x, y) en [(x, y) para x en rango (3) para y en el rango (2)]: – MaiaVictor

35

Usted podría utilizar itertools.product():

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

El múltiplo repiten xrange() declaraciones podrían expresarse como tal, si desea escalar este hasta un diez lazo de dimensiones o algo similarmente ridícula:

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

que las espirales de más de diez variables, que van desde (0,0,0,0,0,0,0,0,0,0) a (2,2,2,2,2,2,2,2,2,2).


En general, itertools es un módulo terriblemente increíble. Del mismo modo que las expresiones regulares son mucho más expresivas que los métodos de cadenas "simples", itertools es una forma muy elegante de expresar bucles complejos. You owe it to yourself to read the itertools module documentation. Hará su vida más divertida.

+0

solo una pequeña mejora con respecto a su última respuesta: 'para c en el producto (* ([xrange (5)] * 3)): imprimir c': from (0 , 0,0) a (4,4,4) – egor83

+0

En realidad, es mejor usar 'itertools.tee()' si quiere réplicas exactas. Creo que la implementación subyacente es más eficiente debido al almacenamiento en caché. –

+0

@ egor83/Li-aung Yip: Por favor, lea los documentos 'itertools' antes de proponer soluciones complicadas. Es 'itertools.product (xrange (3), repeat = 3)'. – agf

3

Puede usar product del módulo itertools.

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

Esa es la cartesian product de dos listas por lo tanto:

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

da este resultado:

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

Me gustaría echar un vistazo a numpy.meshgrid:

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

que le dará los valores de la cuadrícula X e Y en cada posición en una malla/cuadrícula. Posteriormente, se podría hacer algo como:

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

o

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

sería bueno mencionar también 'numpy.mgrid' y' numpy.ogrid' aquí. –

1

de numpy ndindex() trabaja para el ejemplo que dio, pero no sirve a todos los casos de uso. A diferencia del range() incorporado de Python, que permite un arbitrario start, stop y step, np.ndindex() de numpy solo acepta stop. (El start Se presume que (0,0,...) y la step es (1,1,...).)

Aquí es una implementación que actúa más como la incorporada en range() función. Es decir, permite argumentos arbitrarios start/stop/step, pero funciona en tuplas en lugar de meros enteros.

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 

Ejemplo:

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

¡Justo a tiempo para el sprint! – MaiaVictor

Cuestiones relacionadas