如何合并具有相同键或不同键的多个字典?
Posted
技术标签:
【中文标题】如何合并具有相同键或不同键的多个字典?【英文标题】:How to merge multiple dicts with same key or different key? 【发布时间】:2011-08-22 05:16:51 【问题描述】:我有多个这样的字典/键值对:
d1 = key1: x1, key2: y1
d2 = key1: x2, key2: y2
我希望结果是一个新的字典(如果可能,以最有效的方式):
d = key1: (x1, x2), key2: (y1, y2)
实际上,我希望结果 d 是:
d = key1: (x1.x1attrib, x2.x2attrib), key2: (y1.y1attrib, y2.y2attrib)
如果有人告诉我如何获得第一个结果,我可以弄清楚其余的。
【问题讨论】:
@Salil:我们可以假设每个键都存在于所有字典中吗? merging Python dictionaries的可能重复 嗨 Space_C0wb0y,是的,所有字典中都有键。 指定所有字典是否具有相同的键是绝对关键的。 【参考方案1】:使用下面的方法,我们可以合并两个具有相同键的字典。
def update_dict(dict1: dict, dict2: dict) -> dict:
output_dict =
for key in dict1.keys():
output_dict.update(key: [])
if type(dict1[key]) != str:
for value in dict1[key]:
output_dict[key].append(value)
else:
output_dict[key].append(dict1[key])
if type(dict2[key]) != str:
for value in dict2[key]:
output_dict[key].append(value)
else:
output_dict[key].append(dict2[key])
return output_dict
输入:d1 = key1: x1, key2: y1 d2 = key1: x2, key2: y2 输出:'key1': ['x1', 'x2'], 'key2': ['y1', 'y2']
【讨论】:
【参考方案2】:pandas Data Frame
IMO 更好地表示两个或多个具有相同键的字典:
d1 = "key1": "x1", "key2": "y1"
d2 = "key1": "x2", "key2": "y2"
d3 = "key1": "x3", "key2": "y3"
d1_df = pd.DataFrame.from_dict(d1, orient='index')
d2_df = pd.DataFrame.from_dict(d2, orient='index')
d3_df = pd.DataFrame.from_dict(d3, orient='index')
fin_df = pd.concat([d1_df, d2_df, d3_df], axis=1).T.reset_index(drop=True)
fin_df
key1 key2
0 x1 y1
1 x2 y2
2 x3 y3
【讨论】:
【参考方案3】:即使两个字典中的键不同,这个函数也会合并两个字典:
def combine_dict(d1, d2):
return
k: tuple(d[k] for d in (d1, d2) if k in d)
for k in set(d1.keys()) | set(d2.keys())
例子:
d1 =
'a': 1,
'b': 2,
d2` =
'b': 'boat',
'c': 'car',
combine_dict(d1, d2)
# Returns:
# 'a': (1,),
# 'b': (2, 'boat'),
# 'c': ('car',)
#
【讨论】:
【参考方案4】:假设有两个字典具有完全相同的键,下面是最简洁的方法(python3 应该用于两种解决方案)。
d1 = 'a': 1, 'b': 2, 'c':3
d2 = 'a': 5, 'b': 6, 'c':7
# get keys from one of the dictionary
ks = [k for k in d1.keys()]
print(ks)
['a', 'b', 'c']
# call values from each dictionary on available keys
d_merged = k: (d1[k], d2[k]) for k in ks
print(d_merged)
'a': (1, 5), 'b': (2, 6), 'c': (3, 7)
# to merge values as list
d_merged = k: [d1[k], d2[k]] for k in ks
print(d_merged)
'a': [1, 5], 'b': [2, 6], 'c': [3, 7]
如果有两个字典有一些共同的键,但有几个不同的键,则应准备所有键的列表。
d1 = 'a': 1, 'b': 2, 'c':3, 'd': 9
d2 = 'a': 5, 'b': 6, 'c':7, 'e': 4
# get keys from one of the dictionary
d1_ks = [k for k in d1.keys()]
d2_ks = [k for k in d2.keys()]
all_ks = set(d1_ks + d2_ks)
print(all_ks)
['a', 'b', 'c', 'd', 'e']
# call values from each dictionary on available keys
d_merged = k: [d1.get(k), d2.get(k)] for k in all_ks
print(d_merged)
'd': [9, None], 'a': [1, 5], 'b': [2, 6], 'c': [3, 7], 'e': [None, 4]
【讨论】:
【参考方案5】:如果键是嵌套的:
d1 = 'key1': 'nkey1': 'x1' , 'key2': 'nkey2': 'y1'
d2 = 'key1': 'nkey1': 'x2' , 'key2': 'nkey2': 'y2'
ds = [d1, d2]
d =
for k in d1.keys():
for k2 in d1[k].keys():
d.setdefault(k, )
d[k].setdefault(k2, [])
d[k][k2] = tuple(d[k][k2] for d in ds)
产量:
'key1': 'nkey1': ('x1', 'x2'), 'key2': 'nkey2': ('y1', 'y2')
【讨论】:
【参考方案6】:假设您拥有所有键的列表(您可以通过遍历所有字典并获取它们的键来获取此列表)。让我们将其命名为listKeys
。另外:
listValues
是您想要的单个键的所有值的列表
合并。
allDicts
: 你要合并的所有字典。
result =
for k in listKeys:
listValues = [] #we will convert it to tuple later, if you want.
for d in allDicts:
try:
fileList.append(d[k]) #try to append more values to a single key
except:
pass
if listValues: #if it is not empty
result[k] = typle(listValues) #convert to tuple, add to new dictionary with key k
【讨论】:
【参考方案7】:这个库帮助了我,我有一个嵌套键的字典列表,它们具有相同的名称但具有不同的值,所有其他解决方案都不断覆盖这些嵌套键。
https://pypi.org/project/deepmerge/
from deepmerge import always_merger
def process_parms(args):
temp_list = []
for x in args:
with open(x, 'r') as stream:
temp_list.append(yaml.safe_load(stream))
return always_merger.merge(*temp_list)
【讨论】:
【参考方案8】:这是一个通用的解决方案,可以处理任意数量的字典,当键只在一些字典中时:
from collections import defaultdict
d1 = 1: 2, 3: 4
d2 = 1: 6, 3: 7
dd = defaultdict(list)
for d in (d1, d2): # you can list as many input dicts as you want here
for key, value in d.items():
dd[key].append(value)
print(dd)
演出:
defaultdict(<type 'list'>, 1: [2, 6], 3: [4, 7])
另外,要获取您的.attrib
,只需将append(value)
更改为append(value.attrib)
【讨论】:
我认为 OP 想要的值是tuple
而不是 list
。
@A A:真的很重要吗?在多个输入字典的更一般情况下构建元组将更加棘手,其中一些键不存在于任何地方,恕我直言
然后您可能希望从defaultdict
中创建一个正常的dict
,以便您对不存在的键等具有正常的dict
行为:dd = dict(dd)
@Ned:好点,但这取决于数据的最终用途
@Eli:不,这没关系,但我只是试图根据 OP 的要求,并希望你能找到元组的解决方案 :-)【参考方案9】:
来自 blub 的回答:
您也可以使用每个列表中的值直接形成元组
ds = [d1, d2]
d =
for k in d1.keys():
d[k] = (d1[k], d2[k])
如果您对元组有特定的顺序,这可能会很有用
ds = [d1, d2, d3, d4]
d =
for k in d1.keys():
d[k] = (d3[k], d1[k], d4[k], d2[k]) #if you wanted tuple in order of d3, d1, d4, d2
【讨论】:
【参考方案10】:为了补充两个列表的解决方案,这里有一个处理单个列表的解决方案。
一个示例列表(NetworkX 相关;为便于阅读在此处手动格式化):
ec_num_list = [((src, tgt), ec_num['ec_num']) for src, tgt, ec_num in G.edges(data=True)]
print('\nec_num_list:\n'.format(ec_num_list))
ec_num_list:
[((82, 433), '1.1.1.1'),
((82, 433), '1.1.1.2'),
((22, 182), '1.1.1.27'),
((22, 3785), '1.2.4.1'),
((22, 36), '6.4.1.1'),
((145, 36), '1.1.1.37'),
((36, 154), '2.3.3.1'),
((36, 154), '2.3.3.8'),
((36, 72), '4.1.1.32'),
...]
注意相同边的重复值(由元组定义)。将这些“值”与它们对应的“键”进行比较:
from collections import defaultdict
ec_num_collection = defaultdict(list)
for k, v in ec_num_list:
ec_num_collection[k].append(v)
print('\nec_num_collection:\n'.format(ec_num_collection.items()))
ec_num_collection:
[((82, 433), ['1.1.1.1', '1.1.1.2']), ## << grouped "values"
((22, 182), ['1.1.1.27']),
((22, 3785), ['1.2.4.1']),
((22, 36), ['6.4.1.1']),
((145, 36), ['1.1.1.37']),
((36, 154), ['2.3.3.1', '2.3.3.8']), ## << grouped "values"
((36, 72), ['4.1.1.32']),
...]
如果需要,将该列表转换为字典:
ec_num_collection_dict = k:v for k, v in zip(ec_num_collection, ec_num_collection)
print('\nec_num_collection_dict:\n'.format(dict(ec_num_collection)))
ec_num_collection_dict:
(82, 433): ['1.1.1.1', '1.1.1.2'],
(22, 182): ['1.1.1.27'],
(22, 3785): ['1.2.4.1'],
(22, 36): ['6.4.1.1'],
(145, 36): ['1.1.1.37'],
(36, 154): ['2.3.3.1', '2.3.3.8'],
(36, 72): ['4.1.1.32'],
...
参考文献
[此线程]How to merge multiple dicts with same key? [Python 文档]https://docs.python.org/3.7/library/collections.html#collections.defaultdict【讨论】:
【参考方案11】:假设所有键始终存在于所有字典中:
ds = [d1, d2]
d =
for k in d1.iterkeys():
d[k] = tuple(d[k] for d in ds)
注意:在 Python 3.x 中使用以下代码:
ds = [d1, d2]
d =
for k in d1.keys():
d[k] = tuple(d[k] for d in ds)
如果 dic 包含 numpy 数组:
ds = [d1, d2]
d =
for k in d1.keys():
d[k] = np.concatenate(list(d[k] for d in ds))
【讨论】:
我认为只要“for k in d1”就可以了。 和 d.get(k, None) 代替 d[k] @tahir 这意味着字典具有不匹配的键,因此迭代d1
是不正确的(它可能会丢失其他字典中的键)。
对于 python 3 用户:d1.iterkeys() =d1.items()
它在 Python3.x 中仍然对我不起作用。即使我的值不是数组,我也试过这个,它可以工作。但是,输出的值将是数组。 ***.com/questions/54040858/…【参考方案12】:
dict1 = 'm': 2, 'n': 4
dict2 = 'n': 3, 'm': 1
确保键的顺序相同:
dict2_sorted = i:dict2[i] for i in dict1.keys()
keys = dict1.keys()
values = zip(dict1.values(), dict2_sorted.values())
dictionary = dict(zip(keys, values))
给出:
'm': (2, 1), 'n': (4, 3)
【讨论】:
values()
中的元素顺序未定义,因此您可能正在合并来自不相关键的值。
我刚刚应用了更改,因此它现在可以捕获您的反馈
我认为更改不会解决问题。您需要使用sorted(d.items())
或sorted(d.keys())
来获得可预测的结果。
你能举个例子来证明这一点吗? dict2_sorted 是python中的排序字典!
我对此做了一个小的研究。在最新版本的 Python(3.6+)中,迭代顺序开始与插入顺序相匹配(参见例如here),这使您的代码通过。但这被认为是不应依赖的实现细节。我的第二个示例(请参阅here)在使用旧 Python 3.4 的onlinegdb 中确实失败了。其他在线解释器使用较新的 Python,因此无法在此处重现问题。【参考方案13】:
Python 3.x 更新
来自 Eli Bendersky 的回答:
Python 3 删除了 dict.iteritems 改为使用 dict.items。 参见 Python 维基:https://wiki.python.org/moin/Python3.0
from collections import defaultdict
dd = defaultdict(list)
for d in (d1, d2):
for key, value in d.items():
dd[key].append(value)
【讨论】:
【参考方案14】:一个紧凑的可能性
d1='a':1,'b':2
d2='c':3,'d':4
context=**d1, **d2
context
'b': 2, 'c': 3, 'd': 4, 'a': 1
【讨论】:
问题是关于合并具有相同键的字典。你不是必需的答案。【参考方案15】:def merge(d1, d2, merge):
result = dict(d1)
for k,v in d2.iteritems():
if k in result:
result[k] = merge(result[k], v)
else:
result[k] = v
return result
d1 = 'a': 1, 'b': 2
d2 = 'a': 1, 'b': 3, 'c': 2
print merge(d1, d2, lambda x, y:(x,y))
'a': (1, 1), 'c': 2, 'b': (2, 3)
【讨论】:
【参考方案16】:这是您可以使用的一种方法,即使两个字典没有相同的键也可以使用:
d1 = 'a':'test','b':'btest','d':'dreg'
d2 = 'a':'cool','b':'main','c':'clear'
d =
for key in set(d1.keys() + d2.keys()):
try:
d.setdefault(key,[]).append(d1[key])
except KeyError:
pass
try:
d.setdefault(key,[]).append(d2[key])
except KeyError:
pass
print d
这将生成以下输入:
'a': ['test', 'cool'], 'c': ['clear'], 'b': ['btest', 'main'], 'd': ['dreg']
【讨论】:
可以将答案中的set(d1.keys() + d2.keys())
更改为set(list(d1.keys()) + list(d2.keys()))
(对于Python 3.x)吗?否则会在 python3.x 中抛出 TypeError: unsupported operand type(s) for +: 'dict_keys' and 'dict_keys'
错误【参考方案17】:
如果你只有 d1 和 d2,
from collections import defaultdict
d = defaultdict(list)
for a, b in d1.items() + d2.items():
d[a].append(b)
【讨论】:
以上是关于如何合并具有相同键或不同键的多个字典?的主要内容,如果未能解决你的问题,请参考以下文章