2009-08-14 6 views
33

Ce problème me préoccupe depuis longtemps. Existe-t-il un moyen plus simple d'écrire des boucles for imbriquées dans python? Par exemple si mon code est allé quelque chose comme ceci:En python est-il un moyen plus facile d'écrire 6 boucles imbriquées?

for y in range(3): 
    for x in range(3): 
     do_something() 
     for y1 in range(3): 
     for x1 in range(3): 
      do_something_else() 

y aurait-il un moyen plus facile de le faire? Je sais que ce code fonctionne mais quand vous indentez au lieu d'utiliser 2 espaces, comme moi, ça peut devenir un problème. Oh dans l'exemple, il n'y avait que 4 boucles imbriquées for pour faciliter les choses.

+0

[Voir aussi.] (Http://stackoverflow.com/a/533917/1430829) –

Répondre

53

Si vous êtes fréquemment itératif sur un produit cartésien comme dans votre exemple, vous pouvez rechercher Python 2.6's itertools.product - ou écrire le vôtre si vous êtes dans un Python antérieur.

from itertools import product 
for y, x in product(range(3), repeat=2): 
    do_something() 
    for y1, x1 in product(range(3), repeat=2): 
    do_something_else() 
+0

Si la boucle imbriquée comme ceci: ' '' pour y dans la plage (3): do_something1() pour x dans la plage (3): do_something() '' 'comment puis-je utiliser le produit –

+0

@ ErtuğrulAltınboğa Sans indentation, il est impossible de dire ce que vous essayez de faire Je suggère de poser une nouvelle question StackOverflow plutôt que d'essayer d'obtenir de l'aide dans les commentaires –

9

Lorsque je suis confronté à ce genre de logique de programme, je diviserais probablement la séquence de boucles en deux ou plusieurs fonctions distinctes.

Une autre technique en Python consiste à utiliser list comprehensions si possible, au lieu d'une boucle.

2

Mon argument personnel serait que vous faites probablement quelque chose de mal si vous avez 6 boucles imbriquées ...

Cela dit, la décomposition fonctionnelle est ce que vous cherchez. Refactoriser de sorte que certaines des boucles se produisent dans des appels de fonction séparés, puis appeler ces fonctions.

+2

Voici le cas d'utilisation où j'ai eu le dernier nombre de boucles imbriquées: Imaginez l'application d'un filtre 3D flou gaussien à une 3D ensemble de données; vous avez des sommations dans les trois directions pour le filtre (3 boucles), et itération sur chaque point dans trois directions pour l'appliquer (3 boucles de plus). Oh, et les données que je filtrais étaient des vélocités, donc il y avait trois composants à parcourir (1 boucle finale). –

6

En supposant que chaque boucle a une sorte de sens indépendant, briser-les en fonctions nommées:

def do_tigers(): 
    for x in range(3): 
     print something 

def do_lions(): 
    do_lionesses() 
    for x in range(3): 
     do_tigers() 

def do_penguins(): 
    for x in range(3): 
     do_lions() 

..etc. 

Je pourrais peut-être pu choisir de meilleurs noms. 8-)

+3

Aww, pas de chatons :( –

+4

Je ferais les lionnes si j'étais un lion – Skurmedel

+3

Eh bien, c'est une façon d'obtenir des chatons ... Cependant, un peu plus grand que ce que j'avais en tête –

1

De cette façon, semble assez simple et facile. Êtes-vous en train de dire que vous voulez généraliser à plusieurs couches de boucles .... pouvez-vous donner un exemple concret?

Une autre option que je pouvais penser serait d'utiliser une fonction pour générer les paramètres et puis juste les appliquer dans une boucle

def generate_params(n): 
    return itertools.product(range(n), range(n)) 

for x,y in generate_params(3): 
    do_something() 
4

Techniquement, vous pouvez utiliser itertools.product pour obtenir un produit cartésien de séquences N et itérer que:

for y, x, y1, x1 in itertools.product(range(3), repeat=4): 
    do_something_else() 

Mais je ne pense pas que vous gagne quoi que ce soit sage lisibilité.

13

Ceci est assez courant lors de la mise en boucle sur des espaces multidimensionnels.Ma solution est:

xy_grid = [(x, y) for x in range(3) for y in range(3)] 

for x, y in xy_grid: 
    # do something 
    for x1, y1 in xy_grid: 
     # do something else 
+0

Aussi, si vous avez un grand nombre d'éléments à faire défiler, il pourrait être préférable d'utiliser une expression de générateur ie 'xy_grid = ((x, y) pour x dans la plage (30000) pour y dans la plage (30000)). – Garrett

2

De votre code il semble que vous voulez effectuer une opération avec toutes les paires possibles de points où x et y sont dans la gamme 0..2.

Pour cela:

for x1,y1,x2,y2 in itertools.product(range(3), repeat=4): 
    do_something_with_two_points(x1,y1,2,y2) 

L'opération do_something_with_two_points sera appelée 81 fois - une fois pour toutes les combinaisons possibles de points.

3

Les itérateurs Python, et en particulier les générateurs, existent exactement pour permettre le refactoring de boucles complexes. Bien sûr, il est difficile d'extraire une abstraction d'un exemple simple, mais en supposant que le 3 doit être un paramètre (peut-être que le range(3) devrait l'être?), Et les deux fonctions que vous appelez ont besoin de paramètres qui sont des variables de boucle, vous pouvez factoriser le code:

for y in range(3): 
    for x in range(3): 
     do_something(x, y) 
     for y1 in range(3): 
     for x1 in range(3): 
      do_something_else(x, y, x1, y1) 

dans, par exemple:

def nestloop(n, *funcs): 
    head = funcs[0] 
    tail = funcs[1:] 
    for y in range(n): 
    for x in range(n): 
     yield head, x, y 
     if tail: 
     for subtup in nestloop(n, *tail): 
      yield subtup[:1] + (x, y) + subtup[1:] 

for funcandargs in nestloop(3, do_something, do_something_else): 
    funcandargs[0](*funcandargs[1:]) 

le genre exact de refactoring ne doute besoin d'être peaufiné pour vos besoins exacts, mais le point de vue général que itérateurs (et le plus souvent en fait juste des générateurs simples) offrent de très beaux refactorings de boucles de restes - tous les logi en boucle c passe à l'intérieur du générateur, et le code au niveau de l'application est laissé avec for boucles simples et le traitement réel de l'application pertinente des éléments fournis dans les boucles for.

Questions connexes