如果列表具有相同的密钥,则将它们组合在列表中

时间:2017-08-20 00:23:10

标签: python list dictionary sum

我有一个看起来像这样的字典:

{'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中优雅地完成此操作。

4 个答案:

答案 0 :(得分:1)

这使用collections.Counter。这是我能想到的最优雅的,因为你输入的结构略显复杂 - 正如评论所暗示的那样,一长串词典的列表确实可以更好地实现为单个词典。这也是我的代码将其转换为的内容,尽管如果你真的急需旧的数据结构,我已经提供了一些更可能的转换。如果你这样做,我会建议使用元组作为你的键值对,而不仅仅是单长度的dicts,如tuple_output中所示。我建议您使用outputdict_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值