Une seule ligne imbriquée pour les boucles

102

A écrit cette fonction en python qui transpose une matrice:

def transpose(m):
    height = len(m)
    width = len(m[0])
    return [ [ m[i][j] for i in range(0, height) ] for j in range(0, width) ]

Dans le processus, j'ai réalisé que je ne comprenais pas complètement comment les boucles pour une seule ligne imbriquée s'exécutaient. Veuillez m'aider à comprendre en répondant aux questions suivantes:

  1. Quel est l'ordre dans lequel cette boucle for s'exécute?
  2. Si j'avais une triple boucle for imbriquée, quel ordre exécuterait-elle?
  3. Quel serait égal à la boucle for non imbriquée?

Donné,

[ function(i,j) for i,j in object ]
  1. Quel type d'objet doit-il être pour pouvoir l'utiliser pour la structure de la boucle?
  2. Quel est l'ordre dans lequel i et j sont affectés aux éléments dans l'objet?
  3. Peut-il être simulé par une structure de boucle for différente?
  4. Cette boucle for peut-elle être imbriquée avec une structure for loop similaire ou différente? Et à quoi cela ressemblerait-il?

Des informations supplémentaires sont également appréciées.

Guirlande d'Asher
la source

Réponses:

169

La meilleure source d'informations est le tutoriel officiel Python sur la compréhension de liste . Les compréhensions de liste sont presque les mêmes que pour les boucles for (certainement toute compréhension de liste peut être écrite comme une boucle for) mais elles sont souvent plus rapides que l'utilisation d'une boucle for.

Regardez cette compréhension de liste plus longue dans le tutoriel (la ifpartie filtre la compréhension, seules les parties qui passent l'instruction if sont passées dans la partie finale de la compréhension de la liste (ici (x,y)):

>>> [(x, y) for x in [1,2,3] for y in [3,1,4] if x != y]
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]

C'est exactement la même chose que cette boucle imbriquée for (et, comme le dit le tutoriel, notez comment l'ordre de for et if sont les mêmes).

>>> combs = []
>>> for x in [1,2,3]:
...     for y in [3,1,4]:
...         if x != y:
...             combs.append((x, y))
...
>>> combs
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]

La principale différence entre une compréhension de liste et une boucle for est que la dernière partie de la boucle for (où vous faites quelque chose) vient au début plutôt qu'à la fin.

Passons à vos questions:

Quel type d'objet doit-il être pour pouvoir l'utiliser pour la structure de la boucle?

Un itérable . Tout objet pouvant générer un ensemble (fini) d'éléments. Ceux-ci incluent tout conteneur, listes, ensembles, générateurs, etc.

Quel est l'ordre dans lequel i et j sont affectés aux éléments dans l'objet?

Ils sont affectés exactement dans le même ordre qu'ils sont générés à partir de chaque liste, comme s'ils étaient dans une boucle for imbriquée (pour votre première compréhension, vous obtiendrez 1 élément pour i, puis chaque valeur de j, 2ème élément dans i, puis chaque valeur de j, etc.)

Peut-il être simulé par une structure de boucle for différente?

Oui, déjà montré ci-dessus.

Cette boucle for peut-elle être imbriquée avec une structure for loop similaire ou différente? Et à quoi cela ressemblerait-il?

Bien sûr, mais ce n'est pas une bonne idée. Ici, par exemple, vous donne une liste de listes de caractères:

[[ch for ch in word] for word in ("apple", "banana", "pear", "the", "hello")]
Jeff Tratner
la source
Je me demande ce qui a guidé leur choix de commande dans le double emboîtement. Je trouve l'inverse plus naturel (pour y puis pour x dans votre exemple). Je viens de me rendre compte qu'après 3 ans à faire du python (pas beaucoup mais quand même ...) et à utiliser ce genre de boucles !!
Thomas
@Thomas Je trouve aussi l'autre manière plus intuitive. Le choix, je crois, était purement pratique. Le faire de la manière la plus intuitive signifierait devoir gérer des symboles non résolus jusqu'à ce qu'il les trouve plus tard dans la déclaration. Essayez d'analyser chaque banane.Peel dans chaque banane pour chaque city.bananastore dans chaque ville sur papier. Pas aussi simple. L'inverse cependant, agréable et facile.
Pyjong le
29

Vous pourriez être intéressé par itertools.product, qui renvoie un itérable produisant des tuples de valeurs de tous les itérables que vous lui transmettez. Autrement dit, itertools.product(A, B)renvoie toutes les valeurs du formulaire (a, b), d'où aproviennent Ales bvaleurs et d' où proviennent les valeurs B. Par exemple:

import itertools

A = [50, 60, 70]
B = [0.1, 0.2, 0.3, 0.4]

print [a + b for a, b in itertools.product(A, B)]

Cela imprime:

[50.1, 50.2, 50.3, 50.4, 60.1, 60.2, 60.3, 60.4, 70.1, 70.2, 70.3, 70.4]

Remarquez comment l'argument final est passé à itertools.product est celui "intérieur". Généralement, est égal àitertools.product(a0, a1, ... an)[(i0, i1, ... in) for in in an for in-1 in an-1 ... for i0 in a0]

Lynn
la source
4

Tout d'abord, votre premier code n'utilise pas une boucle for en soi, mais une compréhension de liste .

  1. Serait équivalent à

    pour j dans la plage (0, largeur): pour i dans la plage (0, hauteur): m [i] [j]

  2. De la même manière, il s'emboîte généralement comme des boucles, de droite à gauche. Mais la syntaxe de compréhension de liste est plus complexe.

  3. Je ne sais pas ce que cette question pose


  1. Tout objet itérable qui produit des objets itérables qui donnent exactement deux objets (quelle bouchée - c'est-à-dire [(1,2),'ab']serait valide)

  2. L'ordre dans lequel l'objet cède lors de l'itération. iva au premier rendement, jle second.

  3. Oui, mais pas aussi joli. Je pense que c'est fonctionnellement équivalent à:

    l = liste ()
    pour i, j dans l'objet:
        l.append (fonction (i, j))
    

    ou mieux encore utiliser la carte :

    map(function, object)

    Mais bien sûr, la fonction devrait se faire d' elle i- jmême.

  4. N'est-ce pas la même question que 3?

korylprince
la source
2

Vous pouvez utiliser deux boucles for sur la même ligne en utilisant la zipfonction

Code:

list1 = ['Abbas', 'Ali', 'Usman']
list2 = ['Kamran', 'Asgar', 'Hamza', 'Umer']
list3 = []
for i,j in zip(list1,list2):
    list3.append(i)
    list3.append(j)
print(list3)

Production:

['Abbas', 'Kamran', 'Ali', 'Asgar', 'Usman', 'Hamza']

Ainsi, en utilisant la fonction zip, nous pouvons utiliser deux boucles for ou nous pouvons itérer deux listes dans la même ligne.

Muhammad Abbas
la source
-1

Ci-dessous le code pour les meilleurs exemples de boucles imbriquées, tout en utilisant deux boucles for, rappelez-vous que la sortie de la première boucle est entrée pour la deuxième boucle. La terminaison de boucle est également importante lors de l'utilisation des boucles imbriquées

for x in range(1, 10, 1):
     for y in range(1,x):
             print y,
        print
OutPut :
1
1 2
1 2 3
1 2 3 4
1 2 3 4 5
1 2 3 4 5 6
1 2 3 4 5 6 7
1 2 3 4 5 6 7 8
rameshbabu reddy
la source