Python list/dict 通过同一字典中的另一个键对字典列表键求和的理解

Python list/dict comprehension summing a dict list key by another key in the same dict

一直在考虑如果可能的话如何将其转换为一个衬垫:

activities = 
[ {'type': 'Run', 'distance': 12345, 'other_stuff': other ...},                   
  {'type': 'Ride', 'distance': 12345, 'other_stuff': other ...},  
  {'type': 'Swim', 'distance': 12345, 'other_stuff': other ...} ] 

目前正在使用:

grouped_distance = defaultdict(int)
for activity in activities:  
    act_type = activity['type']
    grouped_distance[act_type] += activity['distance']

# {'Run': 12345, 'Ride': 12345, 'Swim': 12345} 

尝试过
grouped_distance = {activity['type']:[sum(activity['distance']) for activity in activities]}
这在它说 activity['type'] 未定义的地方不起作用。

已编辑
修复@Samwise

注意到的一些变量拼写错误

更新: 对发布的所有解决方案做了一些基准测试。 1000 万件物品,10 种不同类型:

方法一(计数器):7.43s
方法二(itertools @chepner):8.64s
方法三(组@Dmig):19.34s
方法四(pandas@d.b):32.73s
方法五(字典@d.b):10.95s

在 Raspberry Pi 4 上测试以进一步查看差异。 如果我错误地“命名”了方法,请纠正我。

谢谢大家,@Dmig、@Mark、@juanpa.arrivillaga 激起了我对性能的兴趣。 Shorter/Neater ≠ 更高的性能。只是想问我是否以单行形式写它以使其看起来更整洁,但我学到的远不止于此。

你的解决方案本身就很好,但如果你真的想要 one-liner:

act = [{'type': 'run', 'distance': 4}, {'type': 'run', 'distance': 3}, {'type': 'swim', 'distance': 5}]

groups = {
  t: sum(i['distance'] for i in act if i['type'] == t)
  for t in {i['type'] for i in act}  # set with all possible activities
}

print(groups)  # {'run': 7, 'swim': 5}

UPD: 我做了一些性能研究,将这个答案与使用 group(sortedby(...)) 的答案进行了比较。事实证明,在一千万个条目和 10 种不同的类型上,这种方法以 18.14 秒输给了 group(sortedby(...))10.12。因此,虽然它更具可读性,但它在更大的列表上效率较低,尤其是其中包含更多不同类型的列表(因为它为每个不同类型迭代一次初始列表)。

但请注意,从问题开始的直接方法只需要 5 秒!

此答案仅供参考 one-liner 用于教育目的,问题的解决方案具有更好的性能。你不应该用这个代替一个有问题的,除非,正如我所说,你真的 want/need one-liner.

使用itertools.groupby.

from operator import itemgetter


by_type = itemgetter('type')
distance = itemgetter('distance')
result = {
    k: sum(map(distance, v))
    for k, v in groupby(sorted(activities, key=by_type), by_type)
    }

当遍历 groupby 实例时,k 将是 activity 类型之一,而 v 将是具有类型 [=13] 的可迭代活动=].