将列表中的项目转换为int并将其汇总的最有效方法

时间:2014-08-19 16:46:03

标签: python file-io io

我做这样的事情来总结一行的许多元素:

for line in open(filename, 'r'):
   big_list = line.strip().split(delim)
   a = sum(int(float(item)) for item in big_list[start:end] if item)  
   # do some other stuff

这是一个大文件一行一行,有些项目可能会丢失,即等于''。如果我使用上面的语句来计算a,那么脚本变得比没有它时慢得多。有没有办法加快速度?

2 个答案:

答案 0 :(得分:0)

正如Padraic评论的那样,使用过滤器修剪掉空字符串,然后删除“if item”:

>>> import timeit
>>> timeit.timeit("sum(int(float(item)) for item in ['','3.4','','','1.0'] if item)",number=10000)
0.04612559381553183
>>> timeit.timeit("sum(int(float(item)) for item in filter(None, ['','3.4','','','1.0']))",number=10000)
0.04827789913997549
>>> sum(int(float(item)) for item in filter(None, ['','3.4','','','1.0']))
4
>>> 

在此示例中会产生相反的效果,但可能会在您的上下文中减少。测量看。

see also this answer

答案 1 :(得分:0)

这还没有经过测试,但直观地说,我希望跳过中间浮动转换会有所帮助。你想要获取小数点左边的整数,所以我会尝试通过正则表达式直接执行:

import re

pattern = re.compile("\d+")

然后用正则表达式匹配替换float解析:

sum(int(pattern.search(item).group(0)) for item in big_list[start:end] if item)

如果您不需要保留旧的十进制字符串,您也可以在构建big_list时动态获取这些字符串。例如,假设我们有一行"6.0,,1.2,3.0,"。我们可以得到这样的匹配:

delim = ","
pattern = re.compile("(\d+)\.\d+|" + re.escape(delim) + re.escape(delim) + "|$")

该模式的结果将是:['6', '', '1', '3', ''],然后可以像往常一样进行切片和过滤,而无需浮点解析:

for line in open(filename, 'r'):
    big_list = pattern.findall(line)
    a = sum(int(item) for item in big_list[start:end] if item)