2009-11-09 4 views
7

voglio fare qualcosa di simile:Python: lista complessi comprehensions dove uno var dipende da un altro (x per x in t [1] per t nei test)

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

test assomiglia:

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

Quindi voglio avere il risultato

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

il mio codice non funziona, dice Python:

UnboundLocalError: local variable 't' referenced before assignment 

C'è un modo semplice per farlo?

+0

Non capisco la necessità della x per x nel tuo caso. Perché non usi tutto = [t [1] per t nei test]? – luc

+0

'[t [1] per t nei test]' restituirà una lista di tuple. '[x for t in tests per x in t [1]]' è una lista semplice (concatenazione di queste tuple). –

risposta

15

Si dovrebbe funzionare il contrario:

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

Grazie, mi chiedo perché non l'ho provato da solo. :) Ho provato tanti modi diversi. – Albert

+15

Penso che la scelta dell'ordine di Python per le liste multiple '' 'sia stata un errore. Capisco che stia cercando di replicare l'uso di istruzioni nidificate, ma trovo i risultati illeggibili e tendono ad evitarlo. – bobince

+1

@bobince +1 totalmente d'accordo, se l'intento era di mantenerlo coerente con il normale 'for', un modo migliore sarebbe stato solo per circondare il blocco con parentesi come' [per x in l: f (x)] ' ; ma in questo caso è più sensato mantenere l'uso e la definizione delle variabili del ciclo più vicine. – fortran

5

In caso di dubbio, non utilizzare list comprehension.

Prova import this nella shell Python e leggere la seconda linea:

Explicit is better than implicit 

Questo tipo di compounding di list comprehension sarà decifrare un sacco di programmatori Python così almeno aggiungere un commento a spiegare che si sta rimuovendo le stringhe e appiattendo la lista rimanente.

Utilizzare le list comprehensions dove sono chiare e facili da capire e, soprattutto, le usiamo quando sono idiomatiche, cioè comunemente usate perché sono il modo più efficiente o elegante per esprimere qualcosa. Ad esempio, this Python Idioms article fornisce il seguente esempio:

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

È chiaro, semplice e lineare. La comprensione delle liste di nidificazione non è male se si presta attenzione alla formattazione e magari si aggiunge un commento perché le parentesi aiutano il lettore a decomporre l'espressione. Ma la soluzione che è stata accettata per questo problema è troppo complessa e confusa secondo me. Oltrepassa i limiti e rende il codice illeggibile per troppe persone. È meglio srotolare almeno un iterazione in un ciclo for.

+0

Spero di aver capito male: * non usare le list comprehensions *. ** Do ** usa le list comprehensions, le operazioni normali (come map) sono molto chiare in questo modo ('[f (x) per x negli elementi]'). – u0b34a0f6ae

+1

Preferisco di gran lunga 'map (f, items)' a '[f (x) per x negli elementi]'. È come un sacco di altri idiomi Python - ad es. 'dict (zip (chiavi, valori))' - in quanto una volta che l'hai interiorizzato, utilizzarlo rende il codice più leggibile eliminando le entità non necessarie. –

+0

+1 per aver sostenuto KISS –

1

Mi sembra riduttivo. Purtroppo Python non offrire alcun zucchero sintattico per ridurre, così abbiamo dovuto usare lambda:

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

Se tutti si sta facendo è l'aggiunta insieme alcune liste, provare la somma builtin, utilizzando [] come valore di partenza:

all = sum((t[1] for t in tests), []) 
Problemi correlati