over - ¿Hay un equivalente de Python de rango(n) para rangos multidimensionales?
python matrix iteration (7)
En Python, el rango (3) devolverá [0,1,2]. ¿Hay un equivalente para rangos multidimensionales?
range((3,2)) # [(0,0),(0,1),(1,0),(1,1),(2,0),(2,1)]
Entonces, por ejemplo, si se repiten las baldosas de un área rectangular en un juego basado en fichas, se puede escribir como:
for x,y in range((3,2)):
Tenga en cuenta que 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.
En numpy, es numpy.ndindex
. También eche un vistazo a numpy.ndenumerate
.
P.ej
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
En realidad hay una sintaxis simple para esto. Solo necesitas 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)]
Ese es el producto cartesiano de dos listas, por lo tanto:
import itertools
for element in itertools.product(range(3),range(2)):
print element
da esta salida:
(0, 0)
(0, 1)
(1, 0)
(1, 1)
(2, 0)
(2, 1)
Numpy''s ndindex()
funciona para el ejemplo que proporcionó, pero no sirve para todos los casos de uso. A diferencia del range()
incorporado de Python range()
, que permite un start
, una stop
y un step
arbitrarios, np.ndindex()
de np.ndindex()
solo acepta una stop
. (Se supone que el start
es (0,0,...)
y el step
es (1,1,...)
.
Aquí hay una implementación que actúa más como la función range()
incorporada. Es decir, permite arbitrarios argumentos de 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)
Puede usar itertools.product()
:
>>> import itertools
>>> for (i,j,k) in itertools.product(xrange(3),xrange(3),xrange(3)):
... print i,j,k
Las múltiples declaraciones de xrange()
repetidas podrían expresarse así, si quieres escalar esto hasta un bucle de diez dimensiones o algo similarmente ridículo:
>>> for combination in itertools.product( xrange(3), repeat=10 ):
... print combination
Que recorre más de diez variables, que varían 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 increíblemente increíble. Del mismo modo, 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. Te debes a ti mismo leer la documentación del módulo itertools
. Hará tu vida más divertida.
Puede usar el product
del módulo itertools
.
itertools.product(range(3), range(2))
numpy.meshgrid
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 grilla X e Y en cada posición en una malla / grilla. Entonces podrías 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)]