web-dev-qa-db-fra.com

"for loop" avec deux variables?

Comment puis-je inclure deux variables dans la même boucle for?

t1 = [a list of integers, strings and lists]
t2 = [another list of integers, strings and lists]

def f(t):  #a function that will read lists "t1" and "t2" and return all elements that are identical
    for i in range(len(t1)) and for j in range(len(t2)):
        ...
96
Quester

Si vous voulez l'effet d'une boucle for imbriquée, utilisez:

import itertools
for i, j in itertools.product(range(x), range(y)):
    # Stuff...

Si vous voulez juste faire une boucle simultanément, utilisez:

for i, j in Zip(range(x), range(y)):
    # Stuff...

Notez que si x et y ne sont pas de même longueur, Zip sera tronqué à la liste la plus courte. Comme @abarnert l'a fait remarquer, si vous ne voulez pas être tronqué à la liste la plus courte, vous pouvez utiliser itertools.Zip_longest.

UPDATE

Sur la base de la demande "d'une fonction qui lit les listes" t1 "et" t2 "et renvoie tous les éléments identiques", je ne pense pas que l'OP souhaite Zip ou product. Je pense qu'ils veulent un set:

def equal_elements(t1, t2):
    return list(set(t1).intersection(set(t2)))
    # You could also do
    # return list(set(t1) & set(t2))

La méthode intersection d'un set renverra tous les éléments qui lui sont communs et un autre ensemble (notez que si vos listes contiennent d'autres lists, vous voudrez peut-être convertir les lists internes en tuples de façon à ce qu'ils soient exécutables; sinon, l'appel à set échouer.). La fonction list transforme ensuite le poste en liste.

PDATE 2

OU, le PO peut vouloir des éléments identiques dans à la même position dans les listes . Dans ce cas, Zip serait le plus approprié, et le fait qu'il soit tronqué sur la liste la plus courte est ce que vous souhaiteriez (puisqu'il est impossible qu'il y ait le même élément à l'index 9 lorsque l'une des listes ne contient que 5 éléments ) Si c'est ce que vous voulez, allez avec ceci:

def equal_elements(t1, t2):
    return [x for x, y in Zip(t1, t2) if x == y]

Cela renverra une liste contenant uniquement les éléments identiques et placés à la même position dans les listes.

169
SethMMorton

Il y a deux questions possibles ici: comment itérer sur ces variables simultanément , ou comment passer en boucle sur leur combinaison .

Heureusement, il existe des réponses simples aux deux. Premier cas, vous voulez utiliser Zip.

x = [1, 2, 3]
y = [4, 5, 6]

for i, j in Zip(x, y):
   print(str(i) + " / " + str(j))

va sortir

1 / 4
2 / 5
3 / 6

Rappelez-vous que vous pouvez mettre tout type itérable dans Zip, de sorte que vous puissiez tout aussi bien écrire votre exemple comme ceci:

for i, j in Zip(range(x), range(y)):
    # do work here.

En fait, je viens de me rendre compte que cela ne marchera pas. Cela ne ferait que répéter jusqu'à épuisement de la plage. Dans ce cas, il semblerait que vous souhaitiez parcourir la combinaison de boucles.

Dans l'autre cas, vous voulez juste une boucle imbriquée.

for i in x:
    for j in y:
        print(str(i) + " / " + str(j))

vous donne

1 / 4
1 / 5
1 / 6
2 / 4
2 / 5
...

Vous pouvez également le faire en tant que compréhension de liste.

[str(i) + " / " + str(j) for i in range(x) for j in range(y)]

J'espère que ça t'as aidé.

30
Morgan Harris

Vous ne pouvez pas utiliser une boucle imbriquée?

for i in range(x):
   for j in range(y):
       #code that uses i and j
20
Jags
for (i,j) in [(i,j) for i in range(x) for j in range(y)]

devrait le faire.

12
qaphla

Si vous avez vraiment juste une itération de verrouillage sur une plage, vous pouvez le faire de plusieurs manières:

for i in range(x):
  j = i
  …
# or
for i, j in enumerate(range(x)):
  …
# or
for i, j in ((i,i) for i in range(x)):
  …

Toutes ces réponses sont équivalentes à for i, j in Zip(range(x), range(y)) si x <= y.

Si vous voulez une boucle imbriquée et que vous ne disposez que de deux itérables, utilisez simplement une boucle imbriquée:

for i in range(x):
  for i in range(y):
    …

Si vous avez plus de deux itérables, utilisez itertools.product.

Enfin, si vous voulez une itération pas à pas jusqu'à x, puis que vous continuiez à y, vous devez décider de ce que devrait être le reste des valeurs x.

for i, j in itertools.Zip_longest(range(x), range(y), fillvalue=float('nan')):
  …
# or
for i in range(min(x,y)):
  j = i
  …
for i in range(min(x,y), max(x,y)):
  j = float('nan')
  …
8
kojiro

"Python 3."

Ajoutez 2 vars avec une boucle for en utilisant Zip et range; Renvoyer une liste.

Remarque: ne fonctionnera que jusqu’à la fin de la plus petite plage.

>>>a=[g+h for g,h in Zip(range(10), range(10))]
>>>a
>>>[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
6
Open-Business

Je pense que vous recherchez des boucles imbriquées.

Exemple (basé sur votre modification):

t1=[1,2,'Hello',(1,2),999,1.23]
t2=[1,'Hello',(1,2),999]

t3=[]

for it1, e1 in enumerate(t1):
    for it2, e2 in enumerate(t2):
        if e1==e2:
            t3.append((it1,it2,e1))

# t3=[(0, 0, 1), (2, 1, 'Hello'), (3, 2, (1, 2)), (4, 3, 999)]

Ce qui peut être réduit à une seule compréhension:

[(it1,it2,e1) for it1, e1 in enumerate(t1) for it2, e2 in enumerate(t2) if e1==e2] 

Mais pour trouver les éléments communs, vous pouvez simplement faire:

print set(t1) & set(t2)
# set([(1, 2), 1, 'Hello', 999])

Si votre liste contient des objets non-hashable (comme d'autres listes, dict), utilisez un ensemble figé:

from collections import Iterable
s1=set(frozenset(e1) if isinstance(e1,Iterable) else e1 for e1 in t1)
s2=set(frozenset(e2) if isinstance(e2,Iterable) else e2 for e2 in t2)
print s1 & s2
3
dawg

Pour votre cas d'utilisation, il peut être plus facile d'utiliser une boucle while .

t1 = [137, 42]
t2 = ["Hello", "world"]

i = 0
j = 0
while i < len(t1) and j < len(t2):
    print t1[i], t2[j]
    i += 1
    j += 1

# 137 Hello
# 42 world

En guise de mise en garde, cette approche sera tronquée à la longueur de votre liste la plus courte.

3
Daniel