【问题标题】:Big for inside for. How can I reduce time?大为内。我怎样才能减少时间?
【发布时间】:2013-09-18 14:39:12
【问题描述】:

我有 2 个列表(“IDS”和“Pay”)。 IDS的len是50000,Pay的len是650000 IDS 是 IDS 的列表,例如 [1,2,3,4,5,6 ... ],而 PAY 列表是包含 IDS 所做的所有付款的列表的列表,例如 [ [1,50], [1,100], [1,60], [2,50], [2,80], [2,50], ...]

要知道每个 ID 总共支付了多少,我在另一个 for 循环中做一个 for 循环,就像这样:

for x in IDS:
    total = 0
    for i in xrange(0,len(Pay)):
        if x == Pay[i][0]:
            total += Pay[i][1]
    print x + str(total)

但是处理这个需要很长时间! 我曾尝试将 Pay 分成 10 份,但仍然花费了太长时间。 任何人都知道如何改进此操作?

谢谢!

【问题讨论】:

  • 对 Pay {IDS: IDSmult} 使用字典。 ~O(1) 而不是 O(n)
  • 使用字典进行支付怎么样?点赞支付 = {1:[50,100,60]},2:[50,80,50,....
  • 如果使用 dict 你也可以删除 IDS。

标签: python loops for-loop logic


【解决方案1】:

你可以使用collections.Counter:

>>> from collections import Counter
>>> pay = [ [1,50], [1,100], [1,60], [2,50], [2,80], [2,50]]
>>> c = Counter()
>>> for idx, amt in pay:
    c[idx] += amt
...     
>>> c
Counter({1: 210, 2: 180})

【讨论】:

  • 很好,不知道收藏!但是,如果“支付”列表有更多信息,例如支付日期 [1,50,2013-09-01],我必须仅对大于 '2013-01-01' 的日期的值求和?
  • @Antonio 只需添加一个if 条件:for idx, amt, dt in pay: if dt > 2013-09-01:c[idx] += amt。 (不要忘记使用datetime.datetime.strptime 将日期字符串转换为日期时间对象。)
  • @Antonio:如果这对你有用,你应该接受这个解决方案=D
【解决方案2】:

好的,事实上你有 2 个很长的列表。与其讨论使用什么库,不如讨论一个更好的算法?

IDs 自然应该包含唯一的整数(我猜),而 Pay 是 (id, payment) 的元组。

现在想想您的列表来自哪里。有两种可能:

  1. 从文件中读取

  2. 来自某些数据库,例如 MySQL

如果是选项 1,则应改为执行以下操作:

from collections import defaultdict
totals = defaultdict(someObj_factory)
[totals[int(line.split[0])].accumulate(someObj_factory(line.split()[1]))
 for line in paymentFile]

首先,您不需要将 id 作为独立列表,因为您在 Pay 中拥有它们。

第二,节省阅读时间。

第三,对于脚本语言,列表理解节省了解释时间。

第四,这是健壮的,因为您可以添加任何您想要的对象,例如日期或元组。

如果是选项 2,请在您的数据库中进行计数-.-

另一种选择是将这些插入数据库,并在那里进行计数。 MySQL 等就是为这种任务而设计的。你会惊讶于它的效率。更多信息:http://mysql-python.sourceforge.net/

【讨论】:

    【解决方案3】:

    如果collections.Counter 不适合您 - 假设您使用的是不同的 Python 版本 - 将您的工资单转换为字典也会产生相同的效果。

    totals = {}
    for id, amount in pay:
       totals[id] = totals.setdefault(id, 0) + amount
    

    像付款日期 [1,50,2013-09-01] 我必须总结 仅限日期大于 '2013-01-01' 的值?

    然后这样做:

    import datetime
    
    base_date = datetime.datetime.strptime('2013-01-01', '%Y-%m-%d').date()
    
    totals = {}
    for idx, amount, pay_date in pay:
       if datetime.datetime.strptime(pay_date, '%Y-%m-%d').date() > base_date:
           totals[idx] = totals.setdefault(id, 0) + amount
    

    【讨论】:

    • 不要使用id作为变量名。
    【解决方案4】:

    您只需要迭代Pay 一次(而不是 50000 次!)。您可以通过散列显着加快计算速度:

    totals = dict(map(lambda id: (id,0), IDS))
    
    for L in Pay:
        if L[0] in totals:
            totals[L[0]] = totals[L[0]] + L[1]
    
    
    for (id, total) in totals.iteritems():
        print "id: %s, total: %d"%(id, total)
    

    【讨论】:

    • 如果所有iPay[i][0]IDS中,那么您可以通过省略包含检查来进一步优化,即if L[0] in totals
    • 即使你不能散列,这种迭代方式仍然是优越的,因为它可能最大化缓存命中。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-23
    • 2012-10-28
    • 1970-01-01
    • 1970-01-01
    • 2021-08-16
    相关资源
    最近更新 更多