Existe-t-il un équivalent Python de range(n) pour les plages multidimensionnelles?
Sur Python, range (3) retournera [0,1,2]. Existe-t-il un équivalent pour les plages multidimensionnelles?
range((3,2)) # [(0,0),(0,1),(1,0),(1,1),(2,0),(2,1)]
Ainsi, par exemple, faire une boucle si les tuiles d'une zone rectangulaire sur un jeu à base de tuiles peuvent être écrites comme:
for x,y in range((3,2)):
Notez que je ne demande pas d'implémentation. Je voudrais savoir s'il s'agit d'un modèle reconnu et s'il existe une fonction intégrée sur Python ou s'il s'agit de bibliothèques standard/communes.
7 réponses
Dans numpy, c'est numpy.ndindex
. Aussi jeter un oeil à numpy.ndenumerate
.
Par exemple
import numpy as np
for x, y in np.ndindex((3,2)):
print x, y
Cela donne:
0 0
0 1
1 0
1 1
2 0
2 1
Vous pouvez utiliser itertools.product()
:
>>> import itertools
>>> for (i,j,k) in itertools.product(xrange(3),xrange(3),xrange(3)):
... print i,j,k
Les multiples instructions xrange()
répétées peuvent être exprimées comme suit, si vous voulez mettre à l'échelle une boucle à dix dimensions ou quelque chose de similaire ridicule:
>>> for combination in itertools.product( xrange(3), repeat=10 ):
... print combination
Qui boucle sur dix variables, variant de (0,0,0,0,0,0,0,0,0,0)
à (2,2,2,2,2,2,2,2,2,2)
.
En général itertools
est un module incroyablement génial. De la même manière, les expressions rationnelles sont beaucoup plus expressives que les méthodes de chaîne "simples", itertools
est une façon très élégante d'exprimer des boucles complexes. Vous vous devez lire la documentation du module itertools
. cela rendra votre vie plus amusante.
Il existe en fait une syntaxe simple pour cela. Vous avez juste besoin d'avoir deux 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)]
Est le produit cartésien de deux listes donc:
import itertools
for element in itertools.product(range(3),range(2)):
print element
Donne cette sortie:
(0, 0)
(0, 1)
(1, 0)
(1, 1)
(2, 0)
(2, 1)
Vous pouvez utiliser product
à partir de itertools
module.
itertools.product(range(3), range(2))
Je voudrais jeter un oeil à numpy.meshgrid
:
Http://docs.scipy.org/doc/numpy-1.6.0/reference/generated/numpy.meshgrid.html
Qui vous donnera les valeurs de grille X et Y à chaque position dans un maillage / grille. Ensuite, vous pouvez faire quelque chose comme:
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)]
Ou
zip(X.ravel(order='F'),Y.ravel(order='F'))
# [(0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1)]
Numpy's ndindex()
fonctionne pour l'exemple que vous avez donné, mais il ne sert pas tous les cas d'utilisation. Contrairement à Python intégré range()
, qui permet à la fois un arbitraire start
, stop
, et step
, numpy's np.ndindex()
n'accepte qu'un stop
. (La start
, est présumé être (0,0,...)
et le step
est (1,1,...)
.)
Voici une implémentation qui agit plus comme la fonction range()
intégrée. C'est, il permet arbitraire start
/stop
/step
arguments, mais il fonctionne sur tuples au lieu de la simple entier.
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
Exemple:
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)