TL;DR
如果需要,请使用@Cat 的解决方案
f: Dict[str, List[Dict[str, int]]] -> Dict[str, Dict[str, int]]
如果你想使用我的
f: Dict[str, List[Dict[str, int]]] -> Dict[str, List[Dict[str, int]]]
解决方案
可能有点矫枉过正,但我想弄乱一些我很少使用的功能。老实说,我不完全确定我正确地注释了这些类型。
import itertools, functools
from typing import Iterator, Iterable, List
def tuple_sum(t1: tuple, t2: tuple) -> tuple:
"""Assumes both `t1` and `t2` are 2-tuples and that they match in the first element."""
(key, x), (_, y) = t1, t2
return (key, x + y)
def tuple_union(tuple_group: itertools.groupby) -> tuple:
"""Unions a group of tuples with matching 'keys', with `tuple_sum` as aggregator."""
return functools.reduce(tuple_sum, tuple_group)
def group_tuples(tuples: Iterable[tuple]) -> itertools.groupby:
"""Yields tuples grouped by key. Assumes `tuples` are already sorted by key."""
yield from (g for _, g in itertools.groupby(tuples, key=lambda t: t[0]))
def package_tuples(tuple_iterator: Iterator[tuple]) -> List[dict]:
"""Packages each tuple in `tuple_iterator` as a standalone `dict`"""
return [dict((t,)) for t in tuple_iterator]
def consolidate(d_list: List[dict]) -> List[dict]:
"""Groups dictionaries with matching keys, then sums their values."""
tuples = []
for d in d_list:
tuples.extend(d.items())
sorted_tuples = sorted(tuples, key=lambda t: t[0])
groups = group_tuples(sorted_tuples)
return package_tuples(tuple_union(g) for g in groups)
用法
>>> {key: consolidate(d_list) for key, d_list in my_dict.items()}
{'key1': [{'A': 0}, {'B': 2}, {'C': 0}, {'D': 0}],
'key2': [{'A': 2}, {'B': 0}, {'C': 0}, {'D': 0}]}
说明
-
tuple_sum() 函数希望非常清晰,它需要两个 2 元组并将它们的第二个元素相加。它假定传递的两个元组具有匹配的“键”,其中“键”被视为第一个元素。
-
tuple_union() 函数获取一组键匹配的元组,例如 [("a", 1), ("a", 5), ("a", 3)],并使用 tuple_sum() 对它们求和,返回一个元组,例如 ("a", 9)。
-
group_tuples() 函数接受一个 sorted 元组迭代,并返回一个生成组的生成器。当具有匹配键的所有元组相邻时,元组的可迭代被认为是“排序的”,例如:[("a", 1), ("a", 5), ("b", 3), ("b", 7), ("b" 3), ("c", 1)]。 itertools.groupby() 函数返回一个生成这些组的迭代器,例如("a", 1), ("a", 5),然后是("b", 3), ("b", 7), ("b" 3)。
-
package_tuples() 函数采用迭代器,该迭代器生成元组并将每个元组打包到字典中,例如 dict((("a", 9),)) -> {"a": 9}。
consolidate() 函数的工作方式是获取一个字典列表并将它们“融合”在一起作为一个大的元组列表。然后它对这些元组进行排序,然后将这些排序后的元组传递给group_tuples 生成器。
替代输出结构
如果您希望将其作为输出:
{'key1': {'A': 0, 'B': 2, 'C': 0, 'D': 0},
'key2': {'A': 2, 'B': 0, 'C': 0, 'D': 0}}
你可以修改consolidate()函数如下:
def consolidate(d_list: List[dict]) -> List[dict]:
"""Groups dictionaries with matching keys, then sums their values."""
tuples = []
for d in d_list:
tuples.extend(d.items())
sorted_tuples = sorted(tuples, key=lambda t: t[0])
return dict(tuple_union(g) for g in group_tuples(sorted_tuples))
这也意味着您可以完全摆脱package_tuples() 函数。不过,在这一点上,@Cat 的解决方案要简洁得多,因为这种类型的合并要简单得多。