2013-07-15 22 views
31
vec = [[1,2,3], [4,5,6], [7,8,9]] 
print [num for elem in vec for num in elem]  <----- this 

>>> [1, 2, 3, 4, 5, 6, 7, 8, 9] 

Questo mi sta ingannando.
Capisco elem è le liste all'interno della lista da for elem in vic
Non capisco l'utilizzo di num e for num in elem all'inizio e alla fine.python list comprehension double per

Come interpreta Python?
Qual è l'ordine in cui guarda?

+0

possibile duplicato del [Doppia iterazione di lista] (http://stackoverflow.com/questions/1198777/double -iteration-in-list-comprehension) –

+3

Questo non è un grande obiettivo dupe, @Inbar, perché non riesce a spiegare nulla su come Python interpreta l'ordine dei loop nidificati. –

+0

Correlato/possibile dupe: [nested list comprehensions] (http://stackoverflow.com/a/11934483) –

risposta

60

Consente di scomporlo.

Un semplice elenco-di comprensione:

[x for x in collection] 

Questo è facile da capire se rompiamo in parti: [A for B in C]

  • A è l'elemento che sarà nella lista risultante
  • B è ogni articolo della collezione C
  • C è la collezione stessa.

In questo modo, si potrebbe scrivere:

[x.lower() for x in words] 

Al fine di convertire tutte le parole in una lista in minuscolo.


è quando abbiamo complicare questo con un altro elenco in questo modo:

[x for y in collection for x in y] # [A for B in C for D in E] 

Qui, qualcosa di speciale accade. Vogliamo che il nostro elenco finale includa gli articoli A e gli articoli A siano trovati all'interno degli articoli B, quindi dobbiamo dire alla lista che lo comprende.

  • A è l'elemento che sarà nella lista risultante
  • B è ogni elemento della collezione C
  • C è la raccolta stessa
  • D è ogni elemento della collezione E (in questo case, anche A)
  • E è un'altra raccolta (in questo caso, B)

Questa logica è simile al normale ciclo for:

for y in collection:  #  for B in C: 
    for x in y:   #   for D in E: (in this case: for A in B) 
     # receive x  #    # receive A 

Per espandere su questo, e dare un grande esempio + spiegazione, immaginiamo che ci sia un treno.

Il motore del treno (parte anteriore) sta andando sempre essere lì (il risultato della lista-di comprensione)

Poi, ci sono un certo numero di vagoni, ogni vagone è in forma: for x in y

un elenco di comprensione potrebbe essere la seguente:

[z for b in a for c in b for d in c ... for z in y] 

che sarebbe come avere questo regolare per-loop:

for b in a: 
    for c in b: 
     for d in c: 
      ... 
       for z in y: 
        # have z 

In altre parole, anziché scendere una riga e rientrare, in una lista di comprensione basta aggiungere il ciclo successivo alla fine.

Per tornare alla stazione un'analogia:

Engine - Car - Car - Car ... Tail

Qual è la coda? La coda è una cosa speciale nella comprensione delle liste. Non hai bisogno di uno, ma se si dispone di una coda, la coda è una condizione, guardare a questo esempio:

[line for line in file if not line.startswith('#')] 

Questo darebbe ogni riga in un file fino a quando la linea di didn' t iniziare con un hashtag (#), altri sono semplicemente saltati.

Il trucco per usare la "coda" del treno è che è controllato per Vero/Falso nello stesso momento in cui hai il tuo 'Motore' o 'risultato' finale da tutti i loop, l'esempio sopra in un regolare per-ciclo sarebbe simile a questa:

for line in file: 
    if not line.startswith('#'): 
     # have line 

si prega di notare: Anche se nella mia analogia di un treno c'è solo una 'coda' alla fine del treno, la condizione o 'coda' può essere dopo ogni 'auto' o loop ...

ad esempio:

>>> z = [[1,2,3,4],[5,6,7,8],[9,10,11,12]] 
>>> [x for y in z if sum(y)>10 for x in y if x < 10] 
[5, 6, 7, 8, 9] 

Nel regolare per-loop:

>>> for y in z: 
    if sum(y)>10: 
     for x in y: 
      if x < 10: 
       print x 

5 
6 
7 
8 
9 
+0

La tua risposta implica che puoi usare solo un'istruzione 'if' alla fine della comprensione di una lista. Quello non è vero. Puoi usare le affermazioni a * qualsiasi * livello nelle tue comprensioni di lista, anche metterne una dopo l'altra (anche se sembra un po 'priva di senso finché non ti accorgi che sono nidificate). Non puoi semplicemente usare un 'se' come * primo * elemento, che deve essere un ciclo' for'. –

+2

Hai ragione, non intendevo implicarlo, lo renderò più chiaro. –

+0

Devo dire che la tua spiegazione complica enormemente le cose. Soprattutto quando inizi ad espandere 'A per B in C per D in E' in un ciclo annidato con' for B in C: 'e' for A in B', scartando la parte 'for D in E'. –

6

Il codice è uguale:

temp = [] 
for elem in vec: 
    for num in elem: 
     temp.append(num) 
+4

Nota che le istruzioni 'for' sono scritte nella lista di comprensione nello stesso ordine in cui sarebbero scritte se tu solo ha scritto regolari cicli 'for' come sopra. – kindall

7

Dal list comprehension documentation:

Quando un elenco di comprensione viene fornito, si compone di una singola espressione seguita da almeno un for clausola e zero o più for o if clausole. In questo caso, gli elementi della nuova lista sono quelli che verrebbero prodotti considerando ognuna delle clausole for o if un blocco, nidificando da sinistra a destra e valutando l'espressione per produrre un elemento list ogni volta che viene raggiunto il blocco più interno .

In altre parole, fingere che i loop for siano nidificati. La lettura da sinistra a destra la lista la vostra comprensione possono essere nidificate come:

for elem in vec: 
    for num in elem: 
     num   # the *single expression* from the spec 

dove la lista di comprensione userà quell'ultimo, blocco più interno come i valori della lista risultante.

Problemi correlati