首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >合并几个字典,根据不同的值创建数组

合并几个字典,根据不同的值创建数组
EN

Stack Overflow用户
提问于 2020-04-30 11:49:56
回答 2查看 500关注 0票数 3

所以我有一个有几本字典的列表,它们都有相同的键。有些字典是一样的,但是一个值是不同的。我如何将它们合并成一个字典,其中包含不同的值作为数组?

让我举一个例子:

假设我有这本字典

代码语言:javascript
复制
[{'a':1, 'b':2,'c':3},{'a':1, 'b':2,'c':4},{'a':1, 'b':3,'c':3},{'a':1, 'b':3,'c':4}]

我想要的输出如下:

代码语言:javascript
复制
[{'a':1, 'b':2,'c':[3,4]},{'a':1, 'b':3,'c':[3,4]}]

我尝试过使用forif嵌套,但它太昂贵和讨厌,我相信一定有更好的方法。能帮我一把吗?

如果字典中的键数量是相同的,并且知道要合并为数组的键的名称(本例中为c),我如何对任何类型的字典这样做?

谢谢!

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-04-30 11:54:34

使用collections.defaultdictc值按ab元组键分组:

代码语言:javascript
复制
from collections import defaultdict

lst = [
    {"a": 1, "b": 2, "c": 3},
    {"a": 1, "b": 2, "c": 4},
    {"a": 1, "b": 3, "c": 3},
    {"a": 1, "b": 3, "c": 4},
]

d = defaultdict(list)
for x in lst:
    d[x["a"], x["b"]].append(x["c"])

result = [{"a": a, "b": b, "c": c} for (a, b), c in d.items()]

print(result)

如果itertools.groupbyb已经订购了lst,也可以使用a

代码语言:javascript
复制
from itertools import groupby
from operator import itemgetter

lst = [
    {"a": 1, "b": 2, "c": 3},
    {"a": 1, "b": 2, "c": 4},
    {"a": 1, "b": 3, "c": 3},
    {"a": 1, "b": 3, "c": 4},
]

result = [
    {"a": a, "b": b, "c": [x["c"] for x in g]}
    for (a, b), g in groupby(lst, key=itemgetter("a", "b"))
]

print(result)

或者,如果lst不是由ab命令的,我们也可以按这两个键进行排序:

代码语言:javascript
复制
result = [
    {"a": a, "b": b, "c": [x["c"] for x in g]}
    for (a, b), g in groupby(
        sorted(lst, key=itemgetter("a", "b")), key=itemgetter("a", "b")
    )
]

print(result)

输出:

代码语言:javascript
复制
[{'a': 1, 'b': 2, 'c': [3, 4]}, {'a': 1, 'b': 3, 'c': [3, 4]}]

更新

对于任何数量的键的更一般的解决方案:

代码语言:javascript
复制
def merge_lst_dicts(lst, keys, merge_key):
    groups = defaultdict(list)

    for item in lst:
        key = tuple(item.get(k) for k in keys)
        groups[key].append(item.get(merge_key))

    return [
        {**dict(zip(keys, group_key)), **{merge_key: merged_values}}
        for group_key, merged_values in groups.items()
    ]

print(merge_lst_dicts(lst, ["a", "b"], "c"))
# [{'a': 1, 'b': 2, 'c': [3, 4]}, {'a': 1, 'b': 3, 'c': [3, 4]}]
票数 3
EN

Stack Overflow用户

发布于 2020-04-30 12:17:40

你可以用临时工来解决这个问题-

代码语言:javascript
复制
>>>python3
Python 3.6.9 (default, Nov  7 2019, 10:44:02) 

>>> di=[{'a':1, 'b':2,'c':3},{'a':1, 'b':2,'c':4},{'a':1, 'b':3,'c':3},{'a':1, 'b':3,'c':4}]
>>> from collections import defaultdict as dd
>>> dt=dd(list) #default dict of list
>>> for d in di: #create temp dict with 'a','b' as tuple and append 'c'
...     dt[d['a'],d['b']].append(d['c'])
>>> for k,v in dt.items(): #Create final output from temp
...     ol.append({'a':k[0],'b':k[1], 'c':v})
... 
>>> ol #output
[{'a': 1, 'b': 2, 'c': [3, 4]}, {'a': 1, 'b': 3, 'c': [3, 4]}]

如果输入dict中的键数很大,则提取temp_dict元组的过程可以自动-

如果键是已知的合并的定义条件,那么它可以是一个常量元组,例如。

代码语言:javascript
复制
keys=('a','b') #in this case, merging happens over these keys

如果在运行时才知道这一点,那么我们可以使用zip函数获得这些键并设置差异,例如。

代码语言:javascript
复制
>>> di
[{'a': 1, 'b': 2, 'c': 3}, {'a': 1, 'b': 2, 'c': 4}, {'a': 1, 'b': 3, 'c': 3}, {'a': 1, 'b': 3, 'c': 4}]
>>> key_to_ignore_for_merge='c'
>>> keys=tuple(set(list(zip(*zip(*di)))[0])-set(key_to_ignore_for_merge))
>>> keys
('a', 'b')

在这一点上,我们可以使用map提取元组作为密钥-

代码语言:javascript
复制
>>> dt=dd(list)
>>> for d in di:
...  dt[tuple(map(d.get,keys))].append(d[key_to_ignore_for_merge])
>>> dt
defaultdict(<class 'list'>, {(1, 2): [3, 4], (1, 3): [3, 4]})

现在,要从default_dict和键重新创建字典,还需要一些压缩魔法!

代码语言:javascript
复制
>>> for k,v in dt.items():
...  dtt=dict(tuple(zip(keys, k)))
...  dtt[key_to_ignore_for_merge]=v
...  ol.append(dtt)
... 
>>> ol
[{'a': 1, 'b': 2, 'c': [3, 4]}, {'a': 1, 'b': 3, 'c': [3, 4]}]

这个解决方案假设您只知道可以不同的键(例如。和rest都是运行时的。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61522699

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档