2013-03-20 9 views
5

Czy istnieje sposób na wydrukowanie dwóch (lub więcej) elementów w iteracji w liście/słowniku/ustawieniu ze zrozumieniem? Prostym przykładem jest wyprowadzenie wszystkich dodatnich i ujemnych podwójnych liczb całkowitych z 1 do 3 (to jest {x | x = ±2n, n ∈ {1...3}}), czy istnieje składnia podobna do następującej?Zrozumienia: wiele wartości na iterację

>>> [2*i, -2*i for i in range(1, 4)] 
[2, -2, 4, -4, 6, -6] 

wiem mogłem krotki wyjściowych (+i,-i) i spłaszczyć, ale zastanawiałem się, czy istnieje jakiś sposób, aby całkowicie rozwiązać problem za pomocą jednego ze zrozumieniem.

Obecnie jestem produkcję dwóch list i ich łączenie (które działa, pod warunkiem, że kolejność nie jest ważna):

>>> [2*i for i in range(1, 4)] + [-2*i for i in range(1, 4)] 
[2, 4, 6, -2, -4, -6] 
+0

pamiętać, że jeśli kolejność nie jest ważna, prawdopodobnie używasz niewłaściwego struktury danych - '{2 * i for i in range (1, 4) } | {-2 * i dla i w zakresie (1, 4)} ". –

+1

@ Klasyczne, które ma efekt uboczny unikania puli elementów wynikowych, co może być pożądane lub nie. –

+0

Dlatego * prawdopodobnie * - jeśli potrzebujesz duplikatów, tak, zestawy są nieodpowiednie. –

Odpowiedz

5

Inną formą zagnieżdżonego zrozumieniem:

>>> [sub for i in range(1, 4) for sub in (2*i, -2*i)] 
[2, -2, 4, -4, 6, -6] 
4

Najlepszą odpowiedzią tutaj jest po prostu użyć itertools.chain.from_iterable() się, jak wspomniałeś, spłaszczyć lista:

itertools.chain.from_iterable((2*i, -2*i) for i in range(1, 4)) 

to jest dość czytelny i nie wymaga Iterowanie nad źródłem dwukrotnie (co może być problematyczne, biorąc pod uwagę niektóre iteratory mogą być wyczerpane, a to oznacza dodatkowy wysiłek obliczeniowej).

+0

Dzięki. To jest dobre rozwiązanie, ale generalnie unikam importowania, chyba że muszę. W pewnym momencie będę musiał dodać itertools do mojego arsenału, więc +1 –

+0

Nie ma powodu, aby odkrywać koło, gdy coś jest w standardowej bibliotece - nie ma powodu, aby bać się 'importu'. 'itertools' jest świetną częścią Pythona (wystarczy sprawdzić, ile odpowiedzi SO Python go używa). Jest szybki, wydajny i robi mnóstwo rzeczy, więc nie musisz. –

4

Chociaż korzystałbym z sugerowanej metody @Lattyware na , jest to bardziej ogólne podejście przy użyciu generatora, który może być również pomocny.

>>> def nums(): 
     for i in range(1, 4): 
      yield 2*i 
      yield -2*i 


>>> list(nums()) 
[2, -2, 4, -4, 6, -6] 
+1

+1, to wystarczająco dobry sposób, aby to zrobić, generatory również wydają się zaskakująco szybko. –

+1

@ Legatware Chciałbym dać ci również +1, ale zabrakło mi – jamylak

+0

XD, pracowity dzień na przeglądzie? –

6

Inną opcją jest zagnieżdżona zrozumieniem:

r = [2*i*s for i in range(1, 4) for s in 1, -1] 

Na bardziej ogólnym przypadku:

r = [item for tpl in (<something that yields tuples>) for item in tpl] 

z oryginalnego przykład:

r = [item for tpl in ((2*i, -2*i) for i in range(1, 4)) for item in tpl] 

chociaż ja naprawdę sugerują itertools.chain.from_iterable jak powiedział @ Installware.

+0

To jest naprawdę eleganckie. –

+0

Należy zauważyć, że ma to na ogół gorszą wydajność, która spłaszcza się za pomocą 'itertools' i jest generalnie bardzo trudna do odczytania (zagnieżdżone spisy na listach są zazwyczaj odrażane przez początkujących ze względu na brak wyraźnej kolejności do odczytania). –

+0

@ Lattyware Czy mógłbyś wyjaśnić, dlaczego miałoby to gorszą wydajność? –

1

Według PEP202 nie ma sposobu na wyjście więcej niż jeden przedmiot z listy zrozumieniem:

- forma [x, y for ...] jest niedozwolone; jeden jest wymagany do napisania [(x, y) for ...].

+0

Jest to prawdziwe tylko w 3.x +, IIRC. W wersji 2.x można użyć poprzedniej metody do skonstruowania krotki, ale w wersji 3.x zmieniono ją tak, aby pasowała do wyrażeń generatora, gdzie nawiasy były wymagane do rozwiązania niejednoznaczności w składni (jak w 3.x, kompilacja list a ich bracia są po prostu syntaktycznym cukrem wokół wyrażeń generujących). –

+0

Po prostu, aby było jasne - w obu wersjach po prostu otrzymujesz krotkę, a nie wiele pozycji na liście. –

+0

Nie rozwiązuje problemu, ale jest to dobra informacja. – nobar