2009-07-29 20 views
118

w Pythonie można mieć wiele iteratorów w listowego, jakPokój Iteracja w listowych

[(x,y) for x in a for y in b] 

dla niektórych odpowiednich sekwencji A i B. Jestem świadomy zagnieżdżonej semantyki języka Pythona.

Moje pytanie brzmi: czy jeden iterator w rozumieniu może odnosić się do drugiego? Innymi słowy: Czy mogę mieć coś takiego:

[x for x in a for a in b] 

gdzie aktualna wartość zewnętrznej pętli jest iteratorem wewnętrznej?

Jako przykład, jeśli mam zagnieżdżonej listy:

a=[[1,2],[3,4]] 

co by lista zrozumienie wyraz być, aby osiągnąć ten wynik:

[1,2,3,4] 

?? (Proszę wymienić tylko odpowiedzi ze zrozumieniem, ponieważ tego właśnie chcę się dowiedzieć).

Odpowiedz

66

Ojej, zgaduję, że znalazłem anwser: nie dbałem o to, która pętla jest wewnętrzna, a która zewnętrzna. Lista rozumienie powinno być tak:

[x for b in a for x in b] 

aby uzyskać pożądany wynik, i tak, jedna wartość prądu może być iterator dla następnej pętli :-). Przepraszamy za hałas.

+33

Składnia ze zrozumieniem listy nie jest jednym z błyskotliwych punktów Pythona. –

+0

@Glenn Tak, łatwo ulega zawiłościom dla więcej niż prostych wyrażeń. – ThomasH

+0

Ew. Nie jestem pewien, czy jest to "zwykłe" użycie dla zrozumienia list, ale bardzo niefortunne jest to, że łańcuchowanie jest tak nieprzyjemne w Pythonie. –

101

Aby odpowiedzieć na to pytanie z własną sugestią:

>>> [x for b in a for x in b] # Works fine 

Podczas poprosił o odpowiedziach lista zrozumieniem, pozwól mi również podkreślić doskonałą itertools.chain():

>>> from itertools import chain 
>>> list(chain.from_iterable(a)) 
>>> list(chain(*a)) # If you're using python < 2.6 
16

ThomasH ma dodano już dobrą odpowiedź, ale chcę pokazać, co się stanie:

>>> a = [[1, 2], [3, 4]] 
>>> [x for x in b for b in a] 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
NameError: name 'b' is not defined 

>>> [x for b in a for x in b] 
[1, 2, 3, 4] 
>>> [x for x in b for b in a] 
[3, 3, 4, 4] 

Chyba Python analizuje zrozumienie listy od lewej do prawej. Oznacza to, że pierwsza przeprowadzona pętla for zostanie wykonana jako pierwsza.

Drugim "problemem" jest to, że b "wyciekło" ze zrozumienia listy. Po pierwszym udanym zrozumieniu listy b == [3, 4].

+3

Interesujący punkt. Zaskoczyło mnie to: 'x = 'hello';' '[x na x w xrange (1,5)];' 'print x # x jest teraz 4' – grinch

+2

Ten wyciek został naprawiony w Pythonie 3: https : //stackoverflow.com/questions/4198906/python-list-comprehension-rebind-names-even-after-scope-of-comprehension-is-thi –

1

czuję, że to jest łatwiejsze do zrozumienia

[row[i] for row in a for i in range(len(a))] 

result: [1, 2, 3, 4] 
44

Mam nadzieję, że to pomoże ktoś inny od a,b,x,y nie mają większego znaczenia dla mnie! Załóżmy, że masz tekst pełen zdań i chcesz zestaw słów.

# Without list comprehension 
list_of_words = [] 
for sentence in text: 
    for word in sentence: 
     list_of_words.append(word) 
return list_of_words 

Lubię rozumieć listę jako rozciąganie kodu w poziomie.

Spróbuj łamiąc go na:

# List Comprehension 
[word for sentence in text for word in sentence] 
+2

Doskonałe wyjaśnienie! – nekomatic

13

Order iteratorów może się wydawać sprzeczne z intuicją.

Weźmy na przykład: [str(x) for i in range(3) for x in foo(i)]

Niech rozkładać go:

def foo(i): 
    return i, i + 0.5 

[str(x) 
    for i in range(3) 
     for x in foo(i) 
] 

# is same as 
for i in range(3): 
    for x in foo(i): 
     yield str(x) 
+1

Co za otwieracz do oczu !! – nehemiah

+0

Rozumiem, że powodem jest to, że "pierwsza iteracja wymieniona jest najwyższą iteracją, która byłaby wpisana, gdyby rozumienie było zapisane jako zagnieżdżone dla pętli". Powodem, dla którego jest to sprzeczne z intuicją, jest to, że pętla OUTER (najwyższa, jeśli jest zapisana jako zagnieżdżone pętle for), pojawia się na WEWNĄTRZ listy/dicta w nawiasach (obiekt zrozumiały). I odwrotnie, pętla INNER (najbardziej wewnętrzna, gdy jest zapisana jako zagnieżdżona pętla for-loop) jest dokładnie prawą pętlą w zrozumieniu iw ten sposób pojawia się na ZEWNĄTRZ rozumienia. –

5

Jeśli chcesz zachować multi tablicy wymiarowe, trzeba gniazdo wsporniki tablicy. patrz przykład poniżej, gdzie jeden jest dodawany do każdego elementu.

>>> a = [[1, 2], [3, 4]] 

>>> [[col +1 for col in row] for row in a] 
[[2, 3], [4, 5]] 

>>> [col +1 for row in a for col in row] 
[2, 3, 4, 5] 
1

Dodatkowo można użyć tylko samą zmienną dla elementu listy wejściowej, która jest aktualnie dostępnym i dla elementu wewnątrz tego elementu. Jednak może to nawet uczynić go bardziej (listą) niezrozumiałym.

input = [[1, 2], [3, 4]] 
[x for x in input for x in x] 

pierwsze for x in input ocenia się, co prowadzi do jednej listy członków wejścia, a następnie Python przeprowadza przez drugą część for x in x w którym wartość X jest zastępowane przez bieżącego elementu jest dostęp, a następnie pierwszy x określa, co chcemy zwrócić.