【问题标题】:Running total for list of dictdict列表的运行总计
【发布时间】:2011-12-16 01:39:37
【问题描述】:

有一个字典的python列表如下:

Dict1 = [{'date': 1, 'name': 'xyz', 'qty': 100},
         {'date': 1, 'name': 'xyz', 'qty': 200},
         {'date': 1, 'name': 'xyz', 'qty': 300},
         {'date': 1, 'name': 'xyz2', 'qty': 30},
         {'date': 2, 'name': 'xyz', 'qty': 1000},
         {'date': 2, 'name': 'xyz2', 'qty': 300},
         {'date': 3, 'name': 'xyz', 'qty': 500},
         {'date': 3, 'name': 'xyz2', 'qty': 500},
         {'date': 3, 'name': 'xyz3', 'qty': 500},
         {'date': 3, 'name': 'xyz', 'qty': 600}]

希望获得每个日期每个名称的运行总数:

date:1,name:xyz,qty:600
date:1,name:xyz2,qty:30
date:2,name:xyz,qty:1600
date:2,name:xyz2,qty:330
date:3,name:xyz,qty:2700
date:3,name:xyz2,qty:830
date:3,name:xyz3,qty:500

谢谢。

【问题讨论】:

    标签: python dictionary


    【解决方案1】:
    from itertools import groupby
    from operator import itemgetter
    for k, gr in groupby(Dict1, key=itemgetter('date', 'name')):
        print "date:%i,name:%s,qty:%i" % (k[0], k[1], sum(d['qty'] for d in gr))
    

    【讨论】:

    • 这没有提供跨日期的运行总计。
    • 那我不知道你在找什么。你能解释一下吗?
    • OP 中描述的输出也不是“运行总数”;这是每个(日期,名称)组合的一个总和。
    • 请注意,如果组尚未排序为在列表中相邻,groupby 将失败,产生额外的块。循环和defaultdict 更健壮,因为不需要对输入列表进行排序,而且不会影响优雅或时间复杂度。
    【解决方案2】:

    我假设日期是递增顺序。

    # store values
    tot = {}
    # the last date 
    date0 = Dict1[-1]['date']
    
    # easier to work from back, i found
    for line in Dict1[-1::-1]:
        date, name, qty = [line[x] for x in 'date', 'name', 'qty']
    
        # add the value to all subsequent days
        for d in range(date, date0+1): 
            tot.setdefault(d, {}).setdefault(name, [0])[0] += qty
    
    # i was putting value into array, and i put it out into a scalar
    tot = dict((k, dict((kk,vv[0]) for kk,vv in v.items())) for k,v in tot.items())
    print tot
    

    结果:

    {1: {'xyz': 600, 'xyz2': 30}, 2: {'xyz': 1600, 'xyz2': 330}, 3: {'xyz': 2700, 'xyz3': 500, 'xyz2': 830}}

    【讨论】:

    • 现在我在实际的日期时间对象中有日期。请帮忙。
    • 减去两个 datetime 对象会得到 timedelta 对象,它具有 .days 属性。它告诉你两个日期时间之间有多少天。您还可以将 timedelta 对象添加/减去 datetime 对象。例如。明天 = datetime.datetime.now() + datetime.timedelta(days=1)。我会将所有日期转换为您的组合的序列日期编号(自您选择的那一天以来的天数)以使数学更容易
    【解决方案3】:

    一个简单的方法是使用collections.defaultdict

    from collections import defaultdict
    
    totals = defaultdict(int)
    
    for d in Dict1:
        name = d['name']
        # increment total
        totals[name] += d['qty']
        print 'date:%s,name:%s,qty:%d' % (d['date'], name, totals[name])
    

    【讨论】:

    • 您可能错过了问题中的for each date 部分:)
    • 看他的预期输出,似乎并没有真正考虑到日期。
    【解决方案4】:

    我只找到了一些复杂的方法:

    items = {}
    for item in Dict1:
        key = (item['date'], item['name'])
        items.setdefault(key, 0)
        items[key] += item['qty']
    
    Dict2 = sorted([dict(date=key[0], name=key[1], qty=qty) for key, qty in items.items()],
        key=labmda x: (x['date', x['name']))
    

    【讨论】:

      【解决方案5】:
      result = {}
      for date, name in [ (d['date'], d['name']) for d in Dict1]:
          result[(date, name)] = sum( [ d['qty'] for d in Dict1 if d['date'] <= date and d['name'] == name] )
      keys = result.keys()
      keys.sort()
      for key in keys:
          print "date:%d, name:%s, qty:%d"%(key[0], key[-1], result[key])
      

      【讨论】:

        猜你喜欢
        • 2023-03-03
        • 1970-01-01
        • 2020-06-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-02-21
        相关资源
        最近更新 更多