2014-09-05 153 views
3

下面的循环在我的程序中创建了一个巨大的瓶颈。特别是因为记录可能超过500k。优化Python循环

records = [item for sublist in records for item in sublist] #flatten the list 
for rec in records: 
    if len(rec) > 5: 
     tag = '%s.%s' %(rec[4], rec[5].strip()) 
     if tag in mydict: 
      mydict[tag][0] += 1 
      mydict[tag][1].add(rec[6].strip()) 
     else: 
      mydict[tag] = [1, set(rec[6].strip())] 

我没有看到一种方法,我可以用字典/列表理解来做到这一点,我不确定调用map对我有多大的好处。有没有什么办法来优化这个循环?

编辑:字典包含有关程序中出现的某些操作的信息。 rec[4]是包含该操作的包,rec[5]是操作的名称。原始日志包含一个int而不是实际名称,所以当日志文件读入列表中时,将查找int并将其替换为操作名称。增量计数器计算操作执行的次数,并且该组包含操作的参数。我正在使用一个集合,因为我不希望重复参数。该条只是为了去除空白。这个空格的存在在rec[6]中是不可预知的,但在rec[4]rec[5]中是一致的。

+2

我看不到一个简单的方法来优化 - 但是,我觉得有必要指出'set(rec [6] .strip())'可能会创建一组单个字符串 - t似乎很喜欢'set.add(rec [6] .strip())',它向该集合添加了一个字符串。 – mgilson 2014-09-05 20:32:15

+4

只要制作'唱片'genexp会有所帮助。 – roippi 2014-09-05 20:32:59

+0

拼合嵌套列表使您的处理时间加倍,不是吗? – jcfollower 2014-09-05 20:40:30

回答

6

相反压扁你可以通过使用itertools.chain.from_iterable其扁平的迭代器直接遍历这样一个庞大的名单。

from itertools import chain 

for rec in chain.from_iterable(records): 
    #rest of the code 

这大约是3倍倍等效嵌套的循环基础genexp版本更快:

In [13]: records = [[None]*500]*10000 

In [14]: %%timeit 
    ...: for rec in chain.from_iterable(records): pass 
    ...: 
10 loops, best of 3: 54.7 ms per loop 

In [15]: %%timeit 
    ...: for rec in (item for sublist in records for item in sublist): pass 
    ...: 
10 loops, best of 3: 170 ms per loop 

In [16]: %%timeit #Your version 
    ...: for rec in [item for sublist in records for item in sublist]: pass 
    ...: 
1 loops, best of 3: 249 ms per loop 
3

我不知道这是否会令或没有,但它的速度更快,而不是有...

if tag in mydict: 
    mydict[tag][0] += 1 
    mydict[tag][1].add(rec[6].strip()) 
else: 
    mydict[tag] = [1, set(rec[6].strip())] 

你可以试试...

element = mydict.setdefault(tag, [0, set()]) 
element[0] += 1 
element[1].add(rec[6], strip())