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.

43
demandé sur MaiaVictor 2012-04-10 21:15:34

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
54
répondu Joe Kington 2012-04-11 00:03:12

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.

36
répondu Li-aung Yip 2012-04-10 17:34:48

Il existe en fait une syntaxe simple pour cela. Vous avez juste besoin d'avoir deux fors:

>>> [(x,y) for x in range(3) for y in range(2)]
[(0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1)]
22
répondu dhg 2012-04-10 17:17:56

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)
6
répondu 0x90 2013-04-03 04:18:57

Vous pouvez utiliser product à partir de itertools module.

itertools.product(range(3), range(2))
3
répondu Praveen Gollakota 2012-04-10 17:18:47

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)]
3
répondu JoshAdel 2012-04-10 18:57:39

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)
1
répondu Stuart Berg 2017-09-21 21:57:43