【问题标题】:List of dict to aggregated list of dict字典列表到字典聚合列表
【发布时间】:2018-03-15 17:40:47
【问题描述】:

我正在寻找一种 Pythonic/优雅的方式来将我的 dict 列表(例如 LD)转换为 dict 的聚合列表(例如 DD)。 LD 中的 dict 有 id、result 和 count 作为键,并且可以有多个具有相同 id 和不同 results 的 dict。生成的字典 DD 应该将 id 聚合在一起,并将所有 results 一起显示(在 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 循环和一个输出 dict 来处理 LD 中的每个项目,但我想知道这是否可以使用诸如 zip 之类的东西在单行中实现。

提前致谢!

【问题讨论】:

  • 你的 dict 对我来说就像另一个 dicts 列表
  • 看起来您想要聚合具有相似 id 的元素。它看起来不像嵌套的字典。
  • 我的错——你是对的!我修正了措辞。感谢您指出。

标签: python python-2.7 dictionary


【解决方案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。
  • @MaggieYing 很高兴为您提供帮助! **用于字典解包,在Python2中可以用于对象参数中的解包,但只有在Python3中才能在其他字典中使用。请参阅我最近的编辑,因为我编写了一个与 Python 2 兼容的解决方案。
  • 这依赖于按 id 预先排序的输入数据。您至少应该提到这一点,因为 OP 没有指定数据是否已排序。
  • 现在是 O(n log n)。这应该在 O(n) 中解决。 –1
  • 对于列表中重复的字典,此解决方案似乎失败。
【解决方案2】:

这是通过collections.defaultdict 提供的解决方案,不依赖于排序+ groupby。

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 所希望的单行。
  • 所以?仅仅因为你可以单线,并不意味着你应该。
  • 我更担心 Ajax 的解决方案不适用于重复的字典,这可能很好 - 但应该注意。
  • @jpp 你能定义“重复字典”吗?
  • [{'id':1, 'result': 'passed', 'count': 10}, {'id':1, 'result': 'passed', 'count': 10}]
猜你喜欢
  • 2019-07-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-11
  • 1970-01-01
  • 2021-12-18
  • 2013-02-19
  • 1970-01-01
相关资源
最近更新 更多