【问题标题】:Most efficient way to convert items of a list to int and sum them up将列表项转换为 int 并将它们相加的最有效方法
【发布时间】:2014-08-19 16:46:03
【问题描述】:

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

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,那么脚本会比没有它时慢得多。有没有办法加快速度?

【问题讨论】:

  • 因为 int('1.0') 引发异常
  • 你在求和什么样的数据,有没有像 3.4 这样的实际浮点数?
  • @jonrsharpe,那更慢
  • 一些快速的timeit 测试表明我可能给了你关于跳过[]s 的坏建议——将列表传递给sum 会稍微快一些。不过,那里的收益可能微乎其微。
  • 有几个问题。我不确定 numpy 或 pandas 是否处理不适合内存的非常大的文件。假设他们这样做,我有几个非常复杂的条件来决定是否处理一条线。所以我不认为我可以使用它们

标签: python file-io io


【解决方案1】:

这未经测试,但直觉上我希望跳过中间浮点转换会有所帮助。你想抓取小数点左边的整数,所以我会尝试直接通过正则表达式来做:

import re

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

然后用正则匹配替换浮点解析:

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)

【讨论】:

  • 实际上,我删除了转换为 int。我只是检查至少有一个非零元素。否则,我放弃了。
【解决方案2】:

正如 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

【讨论】:

    猜你喜欢
    • 2012-02-14
    • 1970-01-01
    • 1970-01-01
    • 2012-11-06
    • 1970-01-01
    • 2013-02-17
    • 2019-08-26
    • 2021-07-08
    • 1970-01-01
    相关资源
    最近更新 更多