2013-09-06 12 views
57

Jak mogę uwzględnić dwie zmienne w tej samej pętli for?"dla pętli" z dwiema zmiennymi?

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)): 
     ... 
+0

Czy X i Y są dwiema listami? – CppLearner

+1

@ user2246674 'zip' jest dobre iff iterables mają tę samą długość. – kojiro

+4

Czy chcesz coś w rodzaju pętli zagnieżdżonej w jednym wierszu, lub po prostu do iteracji na listach jednocześnie? – SethMMorton

Odpowiedz

7
for (i,j) in [(i,j) for i in range(x) for j in range(y)] 

powinno wystarczyć.

+6

To jest trudniejsza do odczytania wersja zagnieżdżonej pętli for w odpowiedzi Matta Quinlana. – abarnert

+1

Wygląda jak początek :) – lionelmessi

14

Dowolny powód, dla którego nie można użyć zagnieżdżonej pętli for?

for i in range(x): 
    for j in range(y): 
     #code that uses i and j 
+1

@Matt: to po prostu nie wyglądało wystarczająco elegancko dla mnie. – Quester

+5

@Quester: Zamiast tego możesz użyć 'product', tak jak w odpowiedzi SethMMorton. Byłoby to z pewnością bardziej eleganckie/czytelne, gdybyś miał sześć zakresów zamiast 2, lub ich liczba była dynamiczna i znana tylko w czasie wykonywania. Ale dla tylko 2 z nich ... trudno jest pokonać 2 zagnieżdżone pętle dla uproszczenia. – abarnert

+0

A kto nie lubi przeglądać wszystkiego, aby uczynić pytona szczęśliwym? – mohbandy

109

Jeśli chcesz efekt zagnieżdżonej pętli for, przeznaczenie:

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

Jeśli chcesz tylko do pętli jednocześnie zastosowanie:

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

Zauważ, że jeśli x i y nie są tej samej długości, zip spowoduje obcięcie do najkrótszej listy. Jak zauważył @abarnert, jeśli nie chcesz skracać do najkrótszej listy, możesz użyć itertools.zip_longest.

UPDATE

Na podstawie wniosku o „funkcji, która będzie czytać list«T1»i«T2»i zwrócić wszystkie elementy, które są identyczne”, nie sądzę, PO chce ziplubproduct. Myślę, że oni chcą set:

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

intersection metoda z set zwróci wszystkie elementy wspólne dla niego i inny zestaw (Zauważ, że jeśli list zawiera inne list s, może chcesz przekonwertować wewnętrzna list s do tuples po raz pierwszy, aby były zgodne z hashable, w przeciwnym razie wywołanie set zakończy się niepowodzeniem.). Funkcja list przekształca następnie zestaw z powrotem na listę.

UPDATE 2

OR, PO może chcieć elementy, które są identyczne w tej samej pozycji w wykazach. W takim przypadku najodpowiedniejszy będzie zip, a fakt, że skraca on do najkrótszej listy, jest tym, czego potrzebujesz (ponieważ niemożliwe jest, aby w indeksie 9 był taki sam element, gdy jedna z list ma tylko 5 elementów). Jeśli to, co chcesz, idź z tym:

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

ta zwróci listę zawierającą tylko te elementy, które są takie same i w tej samej pozycji w listach.

+2

-1 Odpowiedź 'zip' jest niedopasowana.Jak skomentowałem powyżej, działa to tylko jeśli' x = = y' tutaj: – kojiro

+1

@kojiro: Cóż, OP nie określił, co powinno się stać, jeśli 'x! = y'. Gdy to wyjaśni, odpowiedzią będzie albo' zip' albo 'itertools.zip_longest'. – abarnert

+0

@kojiro Lepiej? – SethMMorton

9

Jest tu dwa możliwe pytania: w jaki sposób można iteracyjne nad tymi zmiennymi jednocześnie, lub jak można pętli nad ich połączeniu.

Na szczęście są proste odpowiedzi na oba. Pierwszy przypadek, chcesz użyć zip.

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

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

wyjście wola

1/4 
2/5 
3/6 

Pamiętaj, że możesz umieścić żadnych iterable w zip, więc można równie łatwo pisać exmple jak:

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

Właściwie tylko zdałem sobie sprawę, że to nie zadziała. Byłoby to tylko powtórzenie aż do wyczerpania mniejszego zakresu. W takim przypadku wygląda na to, że chcesz powtórzyć kombinację pętli.

W drugim przypadku potrzebna jest tylko zagnieżdżona pętla.

for i in x: 
    for j in y: 
     print i + "/" + j 

daje

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

Można też to zrobić w postaci listy zrozumieniem.

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

Nadzieję, że pomaga.

5

Jeśli naprawdę wystarczy mieć lock-kroku iteracji w pewnym zakresie, można to zrobić na kilka sposobów:

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)): 
    … 

Wszystkie powyższe są równoważne for i, j in zip(range(x), range(y)) jeśli x <= y.

Jeśli chcesz zagnieżdżonej pętli i masz tylko dwa iterables, wystarczy użyć zagnieżdżonej pętli:

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

Jeśli masz więcej niż dwa iterables użyć itertools.product.

Na koniec, jeśli chcesz wykonać iterację z blokadą aż do x, a następnie przejść do y, musisz zdecydować, jakie powinny być pozostałe wartości 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') 
    … 
1

Myślę, że szukasz zagnieżdżonych pętli.

Przykład (na podstawie swojej Edit):

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)] 

który może być zmniejszona do jednego ze zrozumieniem:

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

ale aby znaleźć wspólne elementy, można po prostu zrobić:

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

Jeśli twoja lista zawiera niehormowane obiekty (jak inne listy, dyktatury) użyj zamrożonego zestawu:

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 
0

"Python 3."

Dodaj 2 vary z pętlą for za pomocą suwaka i zasięgu; Zwracanie listy.

Uwaga: będzie działać, dopóki nie upłynie najmniejszy zakres.

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

Link do Python Docs! https://docs.python.org/3.3/library/stdtypes.html#iterator.__iter__ –