2015-07-26 10 views
12

jest wejście „brudne” lista w pythonPython - rozumienie list w tym przypadku jest wydajne?

input_list = [' \n ',' data1\n ',' data2\n',' \n','data3\n'.....] 

każdy element listy zawiera zarówno puste przestrzenie z nowymi znaków liniowych lub danych z nowej linii znaków

czyszczone przy użyciu kodu poniżej ..

cleaned_up_list = [data.strip() for data in input_list if data.strip()] 

daje

cleaned_up_list = ['data1','data2','data3','data4'..] 

Czy Python wewnętrznie wywołuje strip() dwa razy podczas powyższego rozumienia listy? czy musiałbym użyć jednej iteracji pętli for i tylko raz, jeśli zależy mi na wydajności?

for data in input_list 
    clean_data = data.strip() 
    if(clean_data): 
     cleaned_up_list.append(clean_data) 
+4

Możesz to samemu znaleźć, pisząc niestandardową funkcję, która zwiększa licznik i/lub drukuje za każdym razem, gdy jest wywoływana. –

Odpowiedz

14

Korzystanie z listy zarys pasek jest nazywa dwukrotnie użyć exp gen jeśli chcesz tylko listwy połączeń raz i zachować zrozumieniem:

input_list[:] = [x for x in (s.strip() for s in input_list) if x] 

Wejście:

input_list = [' \n ',' data1\n ',' data2\n',' \n','data3\n'] 

Wyjście:

['data1', 'data2', 'data3'] 

input_list[:] zmieni oryginalną listę, która może być lub nie jest tym, czego chcesz, jeśli rzeczywiście chcesz utworzyć nową listę, po prostu użyj cleaned_up_list = ....

zawsze znaleźć za pomocą itertools.imap w python 2 i map w Pythonie 3 zamiast generatora jest najbardziej efektywny dla większych nakładów:

from itertools import imap 
input_list[:] = [x for x in imap(str.strip, input_list) if x] 

Niektóre taktowania z różnymi podejściami:

In [17]: input_list = [choice(input_list) for _ in range(1000000)] 

In [19]: timeit filter(None, imap(str.strip, input_list)) 
10 loops, best of 3: 115 ms per loop 

In [20]: timeit list(ifilter(None,imap(str.strip,input_list))) 
10 loops, best of 3: 110 ms per loop 

In [21]: timeit [x for x in imap(str.strip,input_list) if x] 
10 loops, best of 3: 125 ms per loop 

In [22]: timeit [x for x in (s.strip() for s in input_list) if x] 
10 loops, best of 3: 145 ms per loop 

In [23]: timeit [data.strip() for data in input_list if data.strip()] 
10 loops, best of 3: 160 ms per loop 

In [24]: %%timeit             
    ....:  cleaned_up_list = [] 
    ....:  for data in input_list: 
    ....:   clean_data = data.strip() 
    ....:   if clean_data: 
    ....:    cleaned_up_list.append(clean_data) 
    ....: 

10 loops, best of 3: 150 ms per loop 

In [25]: 

In [25]: %%timeit              
    ....:  cleaned_up_list = [] 
    ....:  append = cleaned_up_list.append 
    ....:  for data in input_list: 
    ....:   clean_data = data.strip() 
    ....:   if clean_data: 
    ....:    append(clean_data) 
    ....: 

10 loops, best of 3: 123 ms per loop 

Najszybszym podejściem jest w rzeczywistości itertools.ifilter w połączeniu z itertools.imap, a następnie filter z imap.

Usunięcie potrzeby ponownej oceny odwołania do funkcji list.append Każda iteracja jest bardziej wydajna, jeśli utknąłeś w pętli i chciałeś najbardziej efektywnego podejścia, to jest to opłacalna alternatywa.

+1

Czy jest lżejszy niż dwukrotne wywołanie 'strip()'? – clemtoy

+1

Dla dużej ilości danych, tak, ponieważ skonfigurowałeś zrozumienie jeden raz, ale pasek jest wywoływany na każdym elemencie na liście. –

+0

@clemtoy, dodałem pewne czasy dla różnych podejść, możesz zobaczyć, że wywołanie paska dwa razy jest najmniej efektywnym podejściem –

Powiązane problemy