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.
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] 的可迭代活动=].
一直在考虑如果可能的话如何将其转换为一个衬垫:
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.
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] 的可迭代活动=].