【问题标题】:Python list_of_tuples: sum second val of each tuple, only if first val of tuple == somethingPython 元组列表:对每个元组的第二个值求和,仅当元组的第一个值 == 时
【发布时间】:2013-03-21 06:35:40
【问题描述】:

我有一个“标记”元组列表...每个元组是 (tag_id, value)...就像这样:

my_list = [(tag_A, 100), (tag_A, 200), (tag_A, 300), (tag_A, 400), (tag_B, 400), (tag_B, 600)]

我想用相同的标签对每个元组的值求和...这样:

sum_of_all_values_with_tag_A() = 1000

sum_of_all_values_with_tag_B() = 1000

我想不出一个简单的 Pythonic 方法。

sum(set(value for tag_id, value in my_list)) 

...返回所有值的总和。

我想我可以用 for 或 while 循环来包装它,这样只有带有我想要求和的标签的元组才会被那个表达式触及......?我需要将与两个标签关联的值相加......导致两个不同的总数,如上所示。但是不能完全理解这种东西的优雅语法。

这发生在一个预先存在的函数内部。如果没有嵌套函数,那就太好了。

欢迎提出任何建议!

【问题讨论】:

  • 哇。 @Martijn 和hughdbrown:我喜欢both 这两个答案!我认为 Martijn 的回答更贴切地反映了我的想法,但我认为 Hugh 的回答更具可读性/更易于消化。哪个性能更高——速度方面?任何想法? (重要吗?)

标签: python list set tuples


【解决方案1】:

使用生成器表达式对每个标签求和:

sum(val for tag, val in my_list if tag == tag_A)

您可以对标签进行排序,然后使用itertools.groupby 来创建每个标签的组和总和:

from itertools import groupby
from operator import itemgetter

key = itemgetter(0)  # tag
sums = {tag: sum(tup[1] for tup in group)
        for tag, group in groupby(sorted(my_list, key=key), key=key)}

这会产生一个字典,将标签映射到每个标签的总和:

>>> from itertools import groupby
>>> from operator import itemgetter
>>> tag_A, tag_B = 'A', 'B'
>>> my_list = [(tag_A, 100), (tag_A, 200), (tag_A, 300), (tag_A, 400), (tag_B, 400), (tag_B, 600)]
>>> key = itemgetter(0)  # tag
>>> sums = {tag: sum(tup[1] for tup in group)
...         for tag, group in groupby(sorted(my_list, key=key), key=key)}
>>> print sums
{'A': 1000, 'B': 1000}

【讨论】:

  • 在您的第一个解决方案中,您可以将 tup 解压缩为生成器表达式的 for tup in ... 部分中的单独值,这可能会使其他部分更清晰。即sum(value for tag, value in my_list if tag = tag_A)
【解决方案2】:

方法

将您的数据放入defaultdict(list)。总结一下。

代码

from collections import defaultdict
my_list = [('tag_A', 100), ('tag_A', 200), ('tag_A', 300), ('tag_A', 400), ('tag_B', 400), ('tag_B', 600)]

d = defaultdict(list)
for tag, num in my_list:
    d[tag].append(num)

测试

>>> from collections import defaultdict
>>> my_list = [('tag_A', 100), ('tag_A', 200), ('tag_A', 300), ('tag_A', 400), ('tag_B', 400), ('tag_B', 600)]
>>> 
>>> d = defaultdict(list)
>>> for tag, num in my_list:
...     d[tag].append(num)
... 
>>> from pprint import pprint
>>> pprint(dict(d))
{'tag_A': [100, 200, 300, 400], 'tag_B': [400, 600]}
>>> 
>>> pprint({k: sum(v) for k, v in d.iteritems()})
{'tag_A': 1000, 'tag_B': 1000}

替代摘要例程

def summarize_by_tag(d):
    for k, v in d.iteritems():
        print k, sum(v)

>>> summarize_by_tag(d)
tag_A 1000
tag_B 1000

【讨论】:

    【解决方案3】:

    与其他答案一样,我只会使用defaultdict,但除非您以后再次需要这些组。只需在分组时将它们相加即可。 my_list 可能是一个非常大的可迭代对象,并且您不会将整个内容存储在内存中。

    from collections import defaultdict
    my_list = [('tag_A', 100), ('tag_A', 200), ('tag_A', 300), ('tag_A', 400), ('tag_B', 400), ('tag_B', 600)]
    result = defaultdict(int)
    for tag, value in my_list:
        result[tag] += value
    print result
    
    defaultdict(<type 'int'>, {'tag_A': 1000, 'tag_B': 1000})
    

    【讨论】:

      【解决方案4】:

      不导入任何东西。 .

      mysum={}
      my_list = [('tag_A', 100), ('tag_A', 200), ('tag_A', 300), ('tag_A', 400), ('tag_B', 400), ('tag_B', 600)]
      for x in my_list:
          mysum.setdefault(x[0],0)
          mysum[x[0]]+=x[1]
      print mysum
      

      输出::

      {'tag_A': 1000, 'tag_B': 1000}
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2010-10-12
        • 2014-03-14
        • 2019-11-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多