我有一个看起来像这样的字典:
{'Item1': [{'Name1': 3}, {'Name2': 4}, {'Name1':7}],
'Item2': [{'Name7': 44}, {'Name2': 3}, {'Name6':9}, {'Name6':2}]
}
我想在附加到密钥的列表中组合字典,这样如果有多个dicts具有相同的密钥,我可以将它们组合起来(总和)并保留其他字符串。
输出如下:
{'Item1': [{'Name1': 10}, {'Name2': 4}],
'Item2': [{'Name7': 44}, {'Name2': 3}, {'Name6': 11}]
}
我无法通过list / dict理解来理解如何在Python中优雅地完成此操作。
答案 0 :(得分:1)
这使用collections.Counter。这是我能想到的最优雅的,因为你输入的结构略显复杂 - 正如评论所暗示的那样,一长串词典的列表确实可以更好地实现为单个词典。这也是我的代码将其转换为的内容,尽管如果你真的急需旧的数据结构,我已经提供了一些更可能的转换。如果你这样做,我会建议使用元组作为你的键值对,而不仅仅是单长度的dicts,如tuple_output
中所示。我建议您使用output
或dict_output
。
from collections import Counter
d = {'Item1': [{'Name1': 3}, {'Name2': 4}, {'Name1':7}], 'Item2': [{'Name7': 44}, {'Name2': 3}, {'Name6':9}, {'Name6':2}] }
output = {}
for k, v in d.items():
c = Counter()
for sub_dict in v:
c.update(sub_dict)
output[k] = c
dict_output = {k: dict(v) for k, v in output.items()}
tuple_output = {k: v.most_common() for k, v in output.items()}
dict_list_output = {k: [{a: b} for a, b in v.most_common()] for k, v in output.items()}
print(output)
#{'Item1': Counter({'Name1': 10, 'Name2': 4}), 'Item2': Counter({'Name7': 44, 'Name6': 11, 'Name2': 3})}
print(dict_output)
#{'Item1': {'Name1': 10, 'Name2': 4}, 'Item2': {'Name7': 44, 'Name2': 3, 'Name6': 11}}
print(tuple_output)
#{'Item1': [('Name1', 10), ('Name2', 4)], 'Item2': [('Name7', 44), ('Name6', 11), ('Name2', 3)]}
print(dict_list_output)
#{'Item1': [{'Name1': 10}, {'Name2': 4}], 'Item2': [{'Name7': 44}, {'Name6': 11}, {'Name2': 3}]}
当然,如果您完全更改起始数据结构,它将变得更容易管理。如果您使用字符串中的字典到计数器,您可以使用Counter接口轻松更新它(请参阅link)
编辑:
只是为了好玩,一行完成:
results = {item: reduce(lambda a, b: [a, a.update(b)][0], names, Counter()) for item, names in d.items()}
它受到了你的启发,除了它只为每个列表构建一个Counter实例(作为reduce的初始值)。此外,当Counter.update到位时,需要一点点高尔夫球技巧才能正确减少。如果您正在阅读本文,那么您可能不应该使用它,而是从一开始就使用Counters或dicts构建数据结构,如前所述。
答案 1 :(得分:1)
假设您确实希望将其折叠为单个dict
vs list[dict]
,那么您可以在没有任何其他模块的情况下执行此操作,其中包含几个简单的for
循环:
In []:
r = {}
for k, ds in data.items():
s = {}
for d in ds:
for v, c in d.items():
s[v] = s.get(v, 0) + c
r[k] = s
r
Out[]:
{'Item1': {'Name1': 10, 'Name2': 4}, 'Item2': {'Name2': 3, 'Name6': 11, 'Name7': 44}}
有些人似乎想换一个衬垫:
In []:
import itertools as it
from collections import Counter
{k: dict(Counter(v for v, c in it.chain.from_iterable(d.items() for d in ds))
for _ in range(c)) for k, ds in data.items()}
Out[]:
{'Item1': {'Name1': 10, 'Name2': 4}, 'Item2': {'Name2': 3, 'Name6': 11, 'Name7': 44}}
答案 2 :(得分:0)
在发布问题后几分钟我就想到了。
这就是我所做的:
height
正如上面的评论和答案所示,我最好使用1长字典,而不是稍后合并几个。仍然,将答案留给任何需要它的人。
答案 3 :(得分:0)
也可以尝试使用defaultdict
from itertools import chain
from collections import defaultdict
d_new = {}
for k, v in d.items():
d_dict = defaultdict(int)
for k1, v1 in chain(*[ i.items() for i in v ]) :
d_dict[k1]+= v1
d_new[k] = dict(d_dict)
print (d_new)
输出:
{'Item1': {'Name1': 10, 'Name2': 4}, 'Item2': {'Name7': 44, 'Name2': 3, 'Name6': 11}}
chain(* [i.items()for i in v])将dicts列表展平为项目列表
将转换
[{'Name1': 3}, {'Name2': 4}, {'Name1':7}]
到
[('Name1', 3), ('Name2', 4), ('Name1', 7)]
defaultdict(int)用于添加具有相同键的dict值