字典列表转换为聚合后的字典列表

4
我正在寻找一种优雅的Python方法来将我的字典列表(例如LD)转换为聚合的字典列表(例如DD)。 LD中的字典具有idresultcount作为键,可以有多个具有不同result的相同id的字典。生成的DD应该将这些id聚合在一起,并将所有result一起显示(在results中)。
以下是一个示例:
LD = [
    {'id':1, 'result': 'passed', 'count': 10},
    {'id':1, 'result': 'failed', 'count': 20},
    {'id':2, 'result': 'failed', 'count': 100}
]

这是我期望的输出结果

DD = [
    {'id':1, 'results': {'passed': 10, 'failed': 20}},
    {'id':2, 'results': {'passed': 10}}
] 

我可以创建一个for循环和一个输出字典来处理LD中的每个条目,但是我想知道是否可以使用像zip等工具在一行代码中实现这个目标。
提前感谢!

1
你的字典嵌套字典看起来对我来说就像另一个字典列表。 - wim
看起来你想要聚合具有相似ID的元素。它看起来不像是一个嵌套字典。 - P.hunter
我的错 - 你是正确的!我已经修正了措辞。感谢你指出来。 - Maggie Ying
2个回答

1
您可以使用 itertools.groupby

import itertools
LD = [
{'id':1, 'result': 'passed', 'count': 10},
{'id':1, 'result': 'failed', 'count': 20},
{'id':2, 'result': 'failed', 'count': 100}
]
new_result = [(a, list(b)) for a, b in itertools.groupby(sorted(LD, key=lambda x:x['id']), key=lambda x:x['id'])]
last_result = [{**{'id':a}, **{'results':{i['result']:i['count'] for i in b}}} for a, b in new_result]

输出:

[{'id': 1, 'results': {'failed': 20, 'passed': 10}}, {'id': 2, 'results': {'failed': 100}}]

编辑:Python2 版本:

new_result = [(a, list(b)) for a, b in itertools.groupby(sorted(LD, key=lambda x:x['id']), key=lambda x:x['id'])]
last_result = [dict([('id', a)]+[('results', {i['result']:i['count'] for i in b})]) for a, b in new_result]

输出:

[{'id': 1, 'results': {'failed': 20, 'passed': 10}}, {'id': 2, 'results': {'failed': 100}}]

感谢您的快速回复,Ajax1234。 ** 是什么意思? Python 2.7 支持吗?我在第一个 ** 处遇到了 SyntaxError: invalid syntax 的错误。 - Maggie Ying
@MaggieYing 很高兴能帮忙!**用于字典解包,虽然它可以用于Python2中对象参数的解包,但只有在Python3中才能用于其他字典。请查看我的最近编辑,因为我编写了一个与Python 2兼容的解决方案。 - Ajax1234
1
这取决于输入数据按ID预先排序。你至少应该提到这一点,因为OP没有指定数据是否已排序。 - wim
现在时间复杂度是O(n log n)。这个问题应该在O(n)内解决。-1 - wim
这个解决方案似乎无法处理列表中重复的字典。 - jpp

1
这是一种使用 collections.defaultdict 的解决方案,不依赖于排序和分组。
from collections import defaultdict

d = defaultdict(lambda: defaultdict(int))

for i in LD:
    d[i['id']][i['result']] += i['count']

res = [{'id': k, 'result': dict(v)} for k, v in d.items()]

# [{'id': 1, 'result': {'failed': 20, 'passed': 10}},
#  {'id': 2, 'result': {'failed': 100}}]

这不是OP所希望的一行代码。 - Ajax1234
那么?仅仅因为你可以写单行代码,不代表你应该这样做。 - wim
我更关心Ajax的解决方案不能用于重复的字典,这可能没问题,但应该注意。 - jpp
@jpp 你可以定义“重复字典”吗? - Ajax1234
[{'id':1, 'result': 'passed', 'count': 10}, {'id':1, 'result': 'passed', 'count': 10}] - jpp

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接