【问题标题】:sum list of dictionary values字典值的总和列表
【发布时间】:2018-11-19 19:04:36
【问题描述】:

我有一个这种形式的字典列表:

[
{'signal_8': 1, 'signal_1': 7, 'signal_10': 5, 'signal_5': 2, 'signal_2': 5, 'signal_6': 3, 'signal_4': 9, 'signal_3': 6, 'signal_9': 4, 'signal_7': 8}, 

{'signal_8': 1, 'signal_1': 7, 'signal_10': 5, 'signal_5': 2, 'signal_2': 5, 'signal_6': 3, 'signal_4': 9, 'signal_3': 6, 'signal_9': 4, 'signal_7': 8},

{'signal_8': 1, 'signal_1': 7, 'signal_10': 5, 'signal_5': 2, 'signal_2': 5, 'signal_6': 3, 'signal_4': 9, 'signal_3': 6, 'signal_9': 4, 'signal_7': 8},
]

我想为列表中的每个元素按键求和:

    {
     'signal_8': 3,
     'signal_1': 21,
     'signal_10': 15,
     'signal_5': 6,
     'signal_2': 15,
     'signal_6': 9,
     'signal_4': 27,
     'signal_3': 18,
     'signal_9': 12,
     'signal_7': 24
    }

我尝试过的如下:

    result = {}
    sm = 0
    for elm in original_list:
        for k,v in elm.items():
            sm += v
            result[k] = sm
    print(result)

但还是不行。

【问题讨论】:

  • 为什么会起作用?对于所有不同的信号,您都有一个数字。查看collections.Counter.defaultdict
  • 我不明白test 在您的代码中的含义。可以create a minimal, complete and verifiable example吗?
  • @daveruinseverything 抱歉,这只是一个拼写错误,我现在更正它

标签: python python-3.x list dictionary


【解决方案1】:

试试这个:

original_list = [
{'signal_8': 1, 'signal_1': 7, 'signal_10': 5, 'signal_5': 2, 'signal_2': 5, 'signal_6': 3, 'signal_4': 9, 'signal_3': 6, 'signal_9': 4, 'signal_7': 8}, 

{'signal_8': 1, 'signal_1': 7, 'signal_10': 5, 'signal_5': 2, 'signal_2': 5, 'signal_6': 3, 'signal_4': 9, 'signal_3': 6, 'signal_9': 4, 'signal_7': 8},

{'signal_8': 1, 'signal_1': 7, 'signal_10': 5, 'signal_5': 2, 'signal_2': 5, 'signal_6': 3, 'signal_4': 9, 'signal_3': 6, 'signal_9': 4, 'signal_7': 8},
]
print({k:sum([x[k] for x in original_list if k in x]) for i in original_list for k,v in i.items()})

输出:

{'signal_8': 3, 'signal_1': 21, 'signal_10': 15, 'signal_5': 6, 'signal_2': 15, 'signal_6': 9, 'signal_4': 27, 'signal_3': 18, 'signal_9': 12, 'signal_7': 24}

请注意,如果有缺失的信号,它只会将其视为零

【讨论】:

  • 你为什么要把zip 字典的键和值放在一起?这就是 OP已经在使用的项目的用途。此外,您无需创建列表,因为您可以遍历 zip 对象。
  • @jonrsharpe 你说的很对,我会编辑我的答案,也给出一个更简单的答案
  • @jonrsharpe 现在好多了
  • 这个答案非常复杂(O(n^2 * m),其中 n 是字典的数量,m 是每个字典的信号数;它多次计算相同的值,只有最后一个值出现在输出),可读性不是很好,如果任何字典缺少任何信号,都会抛出错误。 @saul,你真的应该再看看其他人。
  • 当每个字典中的键不相同时,这将失败。如果它们确实相同,您可以避免循环遍历所有它们,而只需使用 original_list[0] 代替。另请注意,由于您从不使用这些值,k, v in i.items() 可以归结为k in i,并且您不需要创建值列表来对其求和。
【解决方案2】:

您想要的是 Counter 集合类型。 collections 上的 Python 文档描述得最好,但本质上 Counter 是一种特殊的字典,其中所有值都是整数。您可以传递任何密钥,包括不存在的密钥,并添加到它们。例如:

from collections import Counter

original_list = [
    {'signal_8': 1, 'signal_1': 7, 'signal_10': 5, 'signal_5': 2, 'signal_2': 5, 'signal_6': 3, 'signal_4': 9, 'signal_3': 6, 'signal_9': 4, 'signal_7': 8}, 
    {'signal_8': 1, 'signal_1': 7, 'signal_10': 5, 'signal_5': 2, 'signal_2': 5, 'signal_6': 3, 'signal_4': 9, 'signal_3': 6, 'signal_9': 4, 'signal_7': 8},
    {'signal_8': 1, 'signal_1': 7, 'signal_10': 5, 'signal_5': 2, 'signal_2': 5, 'signal_6': 3, 'signal_4': 9, 'signal_3': 6, 'signal_9': 4, 'signal_7': 8},
]

result = Counter()

for elem in original_list:
    for key, value in elem.items():
        result[key] += value

print(result)

编辑:@timgeb 提供了此答案的变体,它在 Counter 对象上原生使用 update() 方法。我建议将其作为最佳答案

【讨论】:

    【解决方案3】:

    使用itertools.groupby,您可以执行类似的操作

    merged_list = sorted(p for l in original_list for p in l.items())
    groups = groupby(merged_list, key=lambda p: p[0])
    result = {signal: sum(pair[1] for pair in pairs) for signal, pairs in groups}
    

    如果您可以假设每个字典包含完全相同的键,则上述可以简化为

    {k: sum(d[k] for d in original_list) for k in original_list[0]}
    

    另请注意,数据分析库pandas 使这些操作变得微不足道:

    In [70]: import pandas as pd
    
    In [72]: pd.DataFrame(original_list).sum()
    Out[72]:
    signal_1     21
    signal_10    15
    signal_2     15
    signal_3     18
    signal_4     27
    signal_5      6
    signal_6      9
    signal_7     24
    signal_8      3
    signal_9     12
    dtype: int64
    

    【讨论】:

    • 这是一个正确的解决方案,但我不一定会推荐它。它很难阅读/解析,也很难维护。
    • 我不反对;如果我在任何类型的共享代码中使用它,我也会把它分开一点;让我们继续做吧。
    【解决方案4】:

    您的代码的问题在于,无论密钥如何,您都在求和 smv。您可以在下面找到重新格式化的有效代码版本。它只是将列表中每个元素的值添加到结果对象中:

    from collections import defaultdict
    
    result = defaultdict(int)
    
    for elm in original_list:
        for k, v in elm.items():
            result[k] += v
    print(result)
    

    或者,您可以使用一个衬垫:

    result = {key: sum(e[key] for e in original_list) for key in original_list[0].keys()}
    

    【讨论】:

    • 保留它可以提高可读性,但值得注意的是迭代字典与迭代其键相同,因此可以在此处删除.keys()
    • @fuglede,这是一个有效的观察。 .keys() 的使用是个人喜好。
    【解决方案5】:

    您当前的代码对所有信号使用一个累加和,而您需要为每个信号单独计算一个总和。

    如果你想让你的原始代码工作,你需要首先检查result中是否存在密钥,如果不存在则预先将其初始化为0。然后累加各个键的总和。

    代码:

    result = {}
    for elm in original_list:
        for k, v in elm.items():
    
            # Initialise it if it doesn't exist
            if k not in result:
                result[k] = 0
    
            # accumulate sum seperately 
            result[k] += v
    
    print(result)
    

    输出:

    {'signal_9': 12, 'signal_8': 3, 'signal_1': 21, 'signal_3': 18, 'signal_2': 15, 'signal_5': 6, 'signal_4': 27, 'signal_7': 24, 'signal_6': 9, 'signal_10': 15}
    

    注意:正如其他人所展示的,为避免自己初始化,您可以改用collections.defaultdict()collections.Counter()

    【讨论】:

      【解决方案6】:

      你可以试试下面的代码

      basedict=siglist[0]
      for k in basedict.keys():
          result=[currdict[k] for currdict in siglist]
          endval=sum(result)
          print("Key %s and sum of values %d"%(k,endval))
      

      输出

      Key signal_9 and sum of values 12
      Key signal_2 and sum of values 15
      Key signal_8 and sum of values 3
      Key signal_5 and sum of values 6
      Key signal_7 and sum of values 24
      Key signal_10 and sum of values 15
      Key signal_1 and sum of values 21
      Key signal_6 and sum of values 9
      Key signal_4 and sum of values 27
      Key signal_3 and sum of values 18
      

      注意:- 因为我们确信所有字典中的所有键都是相同的,所以这个解决方案效果很好。如果您有一个包含不匹配元素的字典,那么它将导致 KeyError 。所以要注意这个限制

      【讨论】:

        【解决方案7】:

        与 daveruinseverything 的回答类似,我会用 Counter 解决这个问题,但要使用它的 update 方法。

        signals 成为您的字典列表。

        >>> from collections import Counter
        >>> c = Counter()
        >>> for d in signals:
        ...     c.update(d)
        ... 
        >>> c
        Counter({'signal_4': 27, 'signal_7': 24, 'signal_1': 21, 'signal_3': 18, 'signal_10': 15, 'signal_2': 15, 'signal_9': 12, 'signal_6': 9, 'signal_5': 6, 'signal_8': 3})
        

        看在 Op 的份上,您能简要描述一下这里发生了什么吗?

        Counter 的工作方式类似于 dict,但其 update 方法将值添加到预先存在的键的值中,而不是覆盖它们。

        【讨论】:

        • 赞成这个,因为它可能是我在实际代码中使用的解决方案。看在 Op 的份上,您能简要描述一下这里发生了什么吗?
        猜你喜欢
        • 2015-12-19
        • 1970-01-01
        • 2023-01-11
        • 2021-02-08
        • 1970-01-01
        • 2020-08-09
        • 2021-05-11
        • 2019-06-13
        • 2023-04-02
        相关资源
        最近更新 更多