2015-07-26 4 views
12

является входом «грязный» список в PythonPython - понимание списка в этом случае эффективно?

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

каждый элемент списка содержит либо пустые пространства с новыми символов строки или данных с новой строки символов

Убирали его, используя код ниже ..

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

дает

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

Является ли python внутренним вызовом strip() дважды во время описанного выше списка? или мне пришлось бы использовать итерацию цикла for и strip() только один раз, если бы я заботился об эффективности?

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

Вы можете найти это сами, написав пользовательскую функцию, которая увеличивает счетчик и/или распечатывает каждый раз, когда он вызывается. –

ответ

14

Использование списка аккомпанемента полосы является вызывается дважды, используйте аехр поколения, если вы хотите только полосы вызова один раз и сохранить понимание:

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

Вход:

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

Выход:

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

input_list[:] изменит первоначальный список, который может быть или не быть тем, что вы хотите, если вы действительно хотите создать новый список, просто используйте cleaned_up_list = ....

Я всегда найти с помощью itertools.imap в Python 2 и map в Python 3 вместо генератора, чтобы быть наиболее эффективным для больших входов:

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

Некоторые тайминги с различными подходами:

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 

Самый быстрый подход - это фактически itertools.ifilter в сочетании с itertools.imap, за которым следует filter с imap.

Снятие необходимости переоценить назначение функции list.append Каждая итерация более эффективна, если вы застряли с петлей и хотите наиболее эффективный подход, тогда это жизнеспособная альтернатива.

+1

Легче ли вызывать 'strip()' дважды? – clemtoy

+1

Для большого количества данных, да, потому что вы устанавливаете один раз один раз, но полоса вызывается для каждого элемента в списке. –

+0

@clemtoy, я добавил несколько таймингов для различных подходов, вы можете видеть, что вызов полосы дважды является наименее эффективным подходом –