2009-11-09 3 views
7

chcę zrobić coś takiego:Python: kompleksowe listowych gdzie jedna zmienna zależy od innego (x dla x w t [1] t w testach)

all = [ x for x in t[1] for t in tests ] 

testów wygląda następująco:

[ ("foo",[a,b,c]), ("bar",[d,e,f]) ] 

Więc chcę mieć wynik

all = [a,b,c,d,e,f] 

Mój kod nie działa, Python mówi:

UnboundLocalError: local variable 't' referenced before assignment 

Czy istnieje prosty sposób na zrobienie tego?

+0

Nie rozumiem potrzeby x na x w twoim przypadku. Dlaczego po prostu nie użyć all = [t [1] dla t w testach]? – luc

+0

'[t [1] dla t w testach]' zwróci listę krotek. '[x dla t w testach dla x in t [1]]' jest płaską listą (konkatenacją tych krotek). –

Odpowiedz

15

To powinno działać na odwrót:

all = [x for t in tests for x in t[1]] 
+0

Dzięki, zastanawiam się, dlaczego sam tego nie przetestowałem. :) Próbowałem na tak wiele różnych sposobów. – Albert

+15

Myślę, że wybór przez Pythona zamówienia na wiele "pojęć" dla list jest błędem. Rozumiem, że próbuje on replikować użycie zagnieżdżonych dla instrukcji, ale uważam, że wyniki są nieczytelne i starają się tego uniknąć. – bobince

+1

@Bobince +1 całkowicie się zgodził, jeśli intencją było utrzymanie spójności z normalnym 'for', lepszym sposobem byłoby po prostu otoczyć blok nawiasami jak' [dla x w l: f (x)] ; ale w tym przypadku zachowanie użycia i definicji zmiennych pętli bliżej ma więcej sensu. – fortran

5

W razie wątpliwości, nie używać wyrażeń listowych.

Spróbuj import this w powłoce Python i zapoznania się z drugą linię:

Explicit is better than implicit 

Ten typ mieszania z listowych będzie puzzle dużo programistów Pythona, więc przynajmniej dodać komentarz wyjaśnić, że usuwasz ciągi i spłaszczając pozostałą listę.

wolno używać wyrażeń listowych, jeżeli są one jasne i łatwe do zrozumienia, a przede wszystkim, czy ich używać, gdy są idiomatyczne, czyli powszechnie stosowane, ponieważ są one najbardziej efektywne i elegancki sposób, aby wyrazić coś. Na przykład, this Python Idioms article podaje następujący przykład:

result = [3*d.Count for d in data if d.Count > 4] 

To jest jasne, proste i jednoznaczne. Zagnieżdżanie listy zagnieżdżonej nie jest złe, jeśli zwracasz uwagę na formatowanie, a może dodajesz komentarz, ponieważ nawiasy klamrowe pomagają czytelnikowi rozłożyć wyrażenie. Ale rozwiązanie, które zostało zaakceptowane dla tego problemu, jest moim zdaniem zbyt skomplikowane i mylące. Przekracza granice i sprawia, że ​​kod jest nieczytelny dla zbyt wielu osób. Lepiej jest rozwinąć przynajmniej jedną iterację w pętlę for.

+0

Mam nadzieję, że rozumiem, że się mylisz: * nie korzystaj ze spisanych słów *. ** Do ** używają wyrażeń listowych, zwykłe operacje (takie jak mapa) są bardzo wyraźne w ten sposób ('[f (x) dla x w pozycjach]'). – u0b34a0f6ae

+1

Znacznie wolę 'map (f, items)' na '[f (x) dla x w pozycjach]'. To jest jak wiele innych idiomów Pythona - np. 'dict (zip (keys, values))' - po zinternalizowaniu go, użycie go sprawia, że ​​kod staje się bardziej czytelny, eliminując niepotrzebne elementy. –

+0

+1 za promowanie KISS –

1

To wygląda na zredukowanie do mnie. Niestety Python nie oferuje żadnych syntaktyczne cukru dla zmniejszenia, więc musimy użyć lambda:

reduce(lambda x, y: x+y[1], tests, []) 
2

Jeśli wszystko co robisz jest dodanie kilku list, spróbuj suma wbudowane, używając [] jako wartości początkowej:

all = sum((t[1] for t in tests), []) 
Powiązane problemy