2013-08-06 16 views
132

Ho questa lista annidata:Comprensione delle liste su un elenco annidato?

l = [['40', '20', '10', '30'], ['20', '20', '20', '20', '20', '30', '20'], ['30', '20', '30', '50', '10', '30', '20', '20', '20'], ['100', '100'], ['100', '100', '100', '100', '100'], ['100', '100', '100', '100']] 

Ora, quello che voglio fare è convertire ogni elemento in un elenco di galleggiare. La mia soluzione è questa:

newList = [] 
for x in l: 
    for y in x: 
    newList.append(float(y)) 

Ma questo può essere fatto usando la comprensione di liste annidate, giusto?

quello che ho fatto è:

[float(y) for y in x for x in l] 

Ma poi il risultato è mazzo di 100 di con la somma di 2400.

qualsiasi soluzione, una spiegazione sarebbe molto apprezzato. Grazie!

+12

Vuoi * anche * voler appiattire la tua lista? –

+0

@GregHewgill: OP non ha risposto, ma in base alla risposta che hanno accettato, sembra che volessero mantenere il nesting così com'è. – smci

risposta

195

Ecco come si dovrebbe fare questo con una lista di comprensione nidificato:

[[float(y) for y in x] for x in l] 

Questo darebbe una lista di liste, simile a quello di partenza, tranne con i galleggianti al posto delle corde. Se si desidera una lista semplice, si utilizzerà [float(y) for x in l for y in x].

36
>>> l = [['40', '20', '10', '30'], ['20', '20', '20', '20', '20', '30', '20'], ['30', '20', '30', '50', '10', '30', '20', '20', '20'], ['100', '100'], ['100', '100', '100', '100', '100'], ['100', '100', '100', '100']] 
>>> new_list = [float(x) for xs in l for x in xs] 
>>> new_list 
[40.0, 20.0, 10.0, 30.0, 20.0, 20.0, 20.0, 20.0, 20.0, 30.0, 20.0, 30.0, 20.0, 30.0, 50.0, 10.0, 30.0, 20.0, 20.0, 20.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0] 
2

Sì, è possibile farlo con un tale codice:

l = [[float(y) for y in x] for x in l] 
+0

'[float (y) per y in x per x in l]' questo risulterebbe in un gruppo di 100 con una somma di 2400. –

3

Se non ti piace list comprehension nidificate, è possibile utilizzare la funzione di map pure,

>>> from pprint import pprint 

>>> l = l = [['40', '20', '10', '30'], ['20', '20', '20', '20', '20', '30', '20'], ['30', '20', '30', '50', '10', '30', '20', '20', '20'], ['100', '100'], ['100', '100', '100', '100', '100'], ['100', '100', '100', '100']] 

>>> pprint(l) 
[['40', '20', '10', '30'], 
['20', '20', '20', '20', '20', '30', '20'], 
['30', '20', '30', '50', '10', '30', '20', '20', '20'], 
['100', '100'], 
['100', '100', '100', '100', '100'], 
['100', '100', '100', '100']] 

>>> float_l = [map(float, nested_list) for nested_list in l] 

>>> pprint(float_l) 
[[40.0, 20.0, 10.0, 30.0], 
[20.0, 20.0, 20.0, 20.0, 20.0, 30.0, 20.0], 
[30.0, 20.0, 30.0, 50.0, 10.0, 30.0, 20.0, 20.0, 20.0], 
[100.0, 100.0], 
[100.0, 100.0, 100.0, 100.0, 100.0], 
[100.0, 100.0, 100.0, 100.0]] 
+0

Il tuo codice genera oggetti mappa invece di elenchi: '>>> float_l = [ map (float, nested_list) per nested_list in l] ' ' [[], [], [], [], [], []] ' ma l'aggiunta di un ulteriore invito alla lista funziona come previsto: ' >>> float_l = [elenco (mappa (float, nested_list)) per nested_list in l] ' – pixelperfect

+0

@pixelperfect che è dovuto al (* disinformato * ..) cambia in 'python3' per restituire i generatori fuori dalle comprensioni. – javadba

0

Il modo migliore per farlo a mio parere è usare il pacchetto itertools di python.

>>>import itertools 
>>>l1 = [1,2,3] 
>>>l2 = [10,20,30] 
>>>[l*2 for l in itertools.chain(*[l1,l2])] 
[2, 4, 6, 20, 40, 60] 
16

Non sono sicuro che l'output desiderato è, ma se si sta utilizzando di lista, l'ordine segue l'ordine di cicli nidificati, che si deve a ritroso. Così ho preso la cosa penso che vuoi con:

[float(y) for x in l for y in x] 

Il principio è: utilizzare lo stesso ordine devi usare per iscritto fuori come nidificato per i cicli.

+0

questa dovrebbe essere la risposta, dato che alcune volte non vogliamo quadrare l'iteratool – zinking

+0

questa potrebbe non essere la risposta corretta in quanto genera un elenco non annidato, ma è quello che stavo cercando, specialmente * il principio * . Grazie! –

1

Questo problema può essere risolto senza utilizzare per il ciclo. Il codice di linea singolo sarà sufficiente per questo. Anche l'uso della mappa nidificata con funzione lambda funzionerà qui.

l = [['40', '20', '10', '30'], ['20', '20', '20', '20', '20', '30', '20'], ['30', '20', '30', '50', '10', '30', '20', '20', '20'], ['100', '100 '], [' 100' , '100', '100', '100', '100'], [ '100', '100', '100', '100']]

map(lambda x:map(lambda y:float(y),x),l) 

E l'elenco di output sarebbe il seguente:

[[40,0, 20,0, 10,0, 30,0], [20,0, 20,0, 20,0, 20,0, 30,0, 20,0], [30,0, 20,0, 30,0, 50,0, 10,0, 30.0, 20.0, 20.0, 20.0], [100.0, 100.0], [100.0, 100.0, 100.0, 100.0, 100.0], [100.0, 100.0, 100.0, 100.0]]

+1

I lambdas hanno dei vantaggi in termini di prestazioni rispetto alle soluzioni di @Andrew Clark o di Harry Binswanger (più la comprensione delle liste di vaniglia)? Come lambda sembra più difficile da leggere. – Splatmistro

18
  l a b c d e f 
      ↓ ↓ ↓ ↓ ↓ ↓ ↓ 
In [1]: l = [ [ [ [ [ [ 1 ] ] ] ] ] ] 
In [2]: for a in l: 
    ...:  for b in a: 
    ...:   for c in b: 
    ...:    for d in c: 
    ...:     for e in d: 
    ...:      for f in e: 
    ...:       print(float(f)) 
    ...:       
1.0 

In [3]: [float(f) 
     for a in l 
    ...:  for b in a 
    ...:   for c in b 
    ...:    for d in c 
    ...:     for e in d 
    ...:      for f in e] 
Out[3]: [1.0] 

#Which can be written in single line as 
In [4]: [float(f) for a in l for b in a for c in b for d in c for e in d for f in e] 
Out[4]: [1.0] 
+0

Super utile! Rende chiaro che i loop (dall'alto verso il basso) sono ordinati da sinistra a destra nel generatore. Questo non è ovvio dato che in '(f (x) per x in l)' pone la seconda riga dell'equivalente del ciclo a sinistra. – user48956

+0

Ottima illustrazione utile della sintassi (leggermente non ovvia a prima vista) delle nidificazioni nidificate. – wom

4

Dato che io sono po 'in ritardo qui, ma ho voluto condividere come effettivamente funziona di lista lista in particolare annidata di comprensione:

New_list= [[float(y) for x in l] 

è in realtà uguale:

New_list=[] 
for x in l: 
    New_list.append(x) 

E ora nested list comprehension:

[[float(y) for y in x] for x in l] 

è uguale a;

new_list=[] 
for x in l: 
    sub_list=[] 
    for y in x: 
     sub_list.append(float(y)) 

    new_list.append(sub_list) 

print(new_list) 

uscita:

[[40.0, 20.0, 10.0, 30.0], [20.0, 20.0, 20.0, 20.0, 20.0, 30.0, 20.0], [30.0, 20.0, 30.0, 50.0, 10.0, 30.0, 20.0, 20.0, 20.0], [100.0, 100.0], [100.0, 100.0, 100.0, 100.0, 100.0], [100.0, 100.0, 100.0, 100.0]] 
2

ho avuto un problema simile per risolvere così mi sono imbattuto in questa domanda. Ho fatto un confronto tra le prestazioni della risposta di Andrew Clark e di Narayan che vorrei condividere.

La differenza principale tra due risposte è il modo in cui si ripetono le liste interne. Uno di questi utilizza lo strumento integrato map, mentre altri utilizza la comprensione degli elenchi. Map function has slight performance advantage to its equivalent list comprehension if it doesn't require the use lambdas. Pertanto, nel contesto di questa domanda, map dovrebbe essere leggermente migliore della comprensione di un elenco.

Consente di eseguire un benchmark delle prestazioni per verificare se è effettivamente vero. Ho usato Python versione 3.5.0 per eseguire tutti questi test. Nel primo gruppo di prove desidero mantenere elementi secondo l'elenco di essere e variare il numero di liste da 10-100,000

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,10))]*10]" 
>>> 100000 loops, best of 3: 15.2 usec per loop 
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,10))]*10]" 
>>> 10000 loops, best of 3: 19.6 usec per loop 

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,10))]*100]" 
>>> 100000 loops, best of 3: 15.2 usec per loop 
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,10))]*100]" 
>>> 10000 loops, best of 3: 19.6 usec per loop 

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,10))]*1000]" 
>>> 1000 loops, best of 3: 1.43 msec per loop 
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,10))]*1000]" 
>>> 100 loops, best of 3: 1.91 msec per loop 

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,10))]*10000]" 
>>> 100 loops, best of 3: 13.6 msec per loop 
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,10))]*10000]" 
>>> 10 loops, best of 3: 19.1 msec per loop 

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,10))]*100000]" 
>>> 10 loops, best of 3: 164 msec per loop 
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,10))]*100000]" 
>>> 10 loops, best of 3: 216 msec per loop 

enter image description here

Nella successiva serie di prove vorrei per aumentare il numero di elementi per liste a .

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,100))]*10]" 
>>> 10000 loops, best of 3: 110 usec per loop 
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,100))]*10]" 
>>> 10000 loops, best of 3: 151 usec per loop 

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,100))]*100]" 
>>> 1000 loops, best of 3: 1.11 msec per loop 
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,100))]*100]" 
>>> 1000 loops, best of 3: 1.5 msec per loop 

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,100))]*1000]" 
>>> 100 loops, best of 3: 11.2 msec per loop 
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,100))]*1000]" 
>>> 100 loops, best of 3: 16.7 msec per loop 

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,100))]*10000]" 
>>> 10 loops, best of 3: 134 msec per loop 
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,100))]*10000]" 
>>> 10 loops, best of 3: 171 msec per loop 

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,100))]*100000]" 
>>> 10 loops, best of 3: 1.32 sec per loop 
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,100))]*100000]" 
>>> 10 loops, best of 3: 1.7 sec per loop 

enter image description here

Diamo passo coraggioso e modificare il numero di elementi in liste essere

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,1000))]*10]" 
>>> 1000 loops, best of 3: 800 usec per loop 
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,1000))]*10]" 
>>> 1000 loops, best of 3: 1.16 msec per loop 

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,1000))]*100]" 
>>> 100 loops, best of 3: 8.26 msec per loop 
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,1000))]*100]" 
>>> 100 loops, best of 3: 11.7 msec per loop 

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,1000))]*1000]" 
>>> 10 loops, best of 3: 83.8 msec per loop 
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,1000))]*1000]" 
>>> 10 loops, best of 3: 118 msec per loop 

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,1000))]*10000]" 
>>> 10 loops, best of 3: 868 msec per loop 
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,1000))]*10000]" 
>>> 10 loops, best of 3: 1.23 sec per loop 

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,1000))]*100000]" 
>>> 10 loops, best of 3: 9.2 sec per loop 
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,1000))]*100000]" 
>>> 10 loops, best of 3: 12.7 sec per loop 

enter image description here

Da questi prova possiamo concludere che map in questo caso ha un vantaggio in termini di prestazioni rispetto alla comprensione delle liste. Questo vale anche se stai provando a trasmettere su int o su str. Per un numero limitato di elenchi con meno elementi per elenco, la differenza è trascurabile. Per elenchi più grandi con più elementi per elenco, è possibile utilizzare map anziché la comprensione di elenchi, ma dipende totalmente dalle esigenze dell'applicazione.

Tuttavia personalmente trovo la comprensione delle liste più leggibile e più idiomatica di map. È uno standard di fatto in Python. Di solito le persone sono più abili e comode (specialmente principianti) nell'usare la comprensione delle liste rispetto allo map.