Appiattimento di un elenco superficiale in Python

| | | | | | | | | | | | | |

C'è un modo semplice per appiattire un elenco di iterabili con una comprensione dell'elenco o, in mancanza, quale considerereste il modo migliore per appiattire un elenco superficiale come questo, bilanciando prestazioni e leggibilità?

Ho provato ad appiattire un elenco del genere con una comprensione dell'elenco annidato, come questo:

[image for image in menuitem for menuitem in list_of_menuitems] 

Ma ho problemi con la varietà NameError lì, perché il nome "menuitem" non è definito. Dopo aver cercato su Google e guardando in giro Stack Overflow, ho ottenuto i risultati desiderati con un'istruzione reduce:

reduce(list.__add__, map(lambda x: list(x ), list_of_menuitems)) 

Ma questo metodo è abbastanza illeggibile perché ho bisogno che list(x) chiami lì perché x è un Django QuerySet oggetto.

Conclusione:

Grazie a tutti coloro che hanno contribuito a questa domanda. Ecco un riassunto di ciò che ho imparato. Lo sto anche trasformando in un wiki della comunità nel caso in cui altri vogliano aggiungere o correggere queste osservazioni.

La mia istruzione di riduzione originale è ridondante ed è meglio scrivere in questo modo:

>>> reduce(list.__add__, (list(mi) for mi in list_of_menuitems)) 

Questa è la sintassi corretta per la comprensione di un elenco annidato (riassunto brillante dF!):

>>> [immagine per mi in list_of_menuitems per immagine in mi] 

Ma nessuno di questi metodi è efficiente quanto l'utilizzo di itertools.chain:

>>> ; da itertools import chain >>> list(chain(*list_of_menuitems)) 

E come osserva @cdleary, probabilmente è meglio evitare * la magia dell'operatore usando chain.from_iterable in questo modo:

>>> catena = itertools.chain.from_iterable([[1,2],[3],[5,89],[],[6]]) >>> print(elenco(catena)) >>> [1, 2, 3, 5, 89, 6]