2013-10-04 12 views
15

Ho una relazione di amore/odio con la comprensione delle liste. Da un lato penso che siano puliti ed eleganti. D'altra parte odio leggerli. (specialmente quelli che non ho scritto) In genere seguo la regola di, rendilo leggibile fino a quando non è richiesta la velocità. Quindi la mia domanda è davvero accademica a questo punto.La comprensione delle liste pitoniche è possibile con questo ciclo?

Desidero un elenco di stazioni da un tavolo le cui stringhe hanno spesso spazi aggiuntivi. Ho bisogno di quegli spazi spogliati. A volte quelle stazioni sono vuote e non dovrebbero essere incluse.

stations = [] 
for row in data: 
    if row.strip(): 
     stations.append(row.strip()) 

che si traduce in questa lista di comprensione:

stations = [row.strip() for row in data if row.strip()] 

Questo funziona abbastanza bene, ma mi viene in mente che sto facendo striscia due volte. Ho intuito che .strip() non era realmente necessario due volte ed è generalmente più lento dell'assegnazione di una variabile.

stations = [] 
for row in data: 
    blah = row.strip() 
    if blah: 
     stations.append(blah) 

Risulta avevo ragione.

> Striptwice list comp 14.5714301669  
> Striptwice loop 17.9919670399 
> Striponce loop 13.0950567955 

Il tempo visualizzato tra i due segmenti del loop, il 2o (striscia una volta) è più veloce. Nessuna vera sorpresa qui. Sono sorpreso che la comprensione delle liste sia solo leggermente più lenta anche se sta facendo una striscia due volte.

La mia domanda: C'è un modo per scrivere una comprensione di lista che fa la striscia solo una volta?



Risultati:

Ecco i risultati di temporizzazione dei suggerimenti

# @JonClements & @ErikAllik 
> Striptonce list comp 10.7998494348 
# @adhie 
> Mapmethod loop 14.4501044569 
+1

Sono curioso di sapere come le risposte suggerite confrontano tempo-saggio per i test – Izkata

+0

Avete intenzione di accettare qualsiasi delle risposte? –

+0

Lo farò. Sono appena tornato al mio posto questa mattina e non ho guardato nulla per tutto il weekend. –

risposta

13

comprensioni nidificate può essere difficile da leggere, quindi la mia prima preferenza sarebbe:

stripped = (x.strip() for x in data) 
stations = [x for x in stripped if x] 

Or , se in linea stripped, si ottiene un singolo (nested) lista di comprensione:

stations = [x for x in (x.strip() for x in data) if x] 

si noti che il primo/interna comprensione è una realtà generatore expressio n, che, in altre parole, è una comprensione di lista pigra; questo per evitare di ripetere due volte.

+0

Analogamente, 'def stripped (iter): return (x.strip() per x in iter)', quindi puoi scrivere 'stations = list (x per x in stripped (data) se x)'. –

+0

Sì, questo ha senso se 'stripped' sarà usato di nuovo in seguito. –

+0

@SteveJessop Anche se la denominazione del parametro 'iterable' è più convenzionale e, cosa più importante, evita l'ombreggiamento del' iter' incorporato nella funzione ... –

29

C'è - creare un generatore delle corde spogliato prima, quindi utilizzare tale:

stations = [row for row in (row.strip() for row in data) if row] 

Si potrebbe anche scrivere i t senza un comp, ad esempio (di swap per imap e rimuovere list per Python 2.x):

stations = list(filter(None, map(str.strip, data))) 
+0

Quindi 'None' sta per la funzione ID (' lambda x: x') in pratica? Non ero a conoscenza di tale scorciatoia; Grazie! –

+1

Btw che la chiamata 'list (...)' non è necessaria. –

+1

@ErikAllik per Python 3.x è ... Ho notato che dovrebbe essere rimosso per Python 2.x così come 'map' viene scambiato per' imap' :) –

1

Applicare la striscia a tutti gli elementi utilizzando map() e filtrare dopo.

[item for item in map(lambda x: x.strip(), list) if item] 
+0

che 'map()' non è necessario né incoraggiato dalla convenzione/comunità Python; inoltre, il tuo codice esegue 2 iterazioni. –

+0

Quindi trasformarlo nel modulo di comprensione dell'elenco. In alcune lingue funzionali, la mappa è più pigra. – adhie

+0

'map' non è pigro in Python ma' itertools.imap' è. –

Problemi correlati