在Python中合并两个包含列表的字典

9

有两个字典

x={1:['a','b','c']}
y={1:['d','e','f'],2:['g']}

我希望得到一个新的字典 z,它是由 x 和 y 合并而成的,满足以下条件:
z = {1:['a','b','c','d','e','f'],2:['g']}

这个操作能做到吗?我尝试了更新操作。

x.update(y)

但是它给了我以下结果。
z= {1:['d','e','f'],2:['g']}
6个回答

8

一行解决方案:

{ key:x.get(key,[])+y.get(key,[]) for key in set(list(x.keys())+list(y.keys())) }

示例1:

x={1:['a','b','c']}
y={1:['d','e','f'],2:['g']}
{ key:x.get(key,[])+y.get(key,[]) for key in set(list(x.keys())+list(y.keys())) }

输出:

{1: ['a', 'b', 'c', 'd', 'e', 'f'], 2: ['g']}

例子2:

one = {'a': [1, 2], 'c': [5, 6], 'b': [3, 4]}
two = {'a': [2.4, 3.4], 'c': [5.6, 7.6], 'd': [3.5, 4.5]}
{ key:one.get(key,[])+two.get(key,[]) for key in set(list(one.keys())+list(two.keys())) }

输出:

{'a': [1, 2, 2.4, 3.4], 'b': [3, 4], 'c': [5, 6, 5.6, 7.6], 'd': [3.5, 4.5]}


3
for k, v in x.items():
if k in y.keys():
    y[k] += v
else:
    y[k] = v

遍历字典获取键和值,检查键是否已存在,如果存在则添加,否则添加新的键和值。如果你的值是混合数据类型而不是列表类型,那么这种方法将行不通。

   x={1:['a','b','c'], 3:['y']} 
.. y={1:['d','e','f'],2:['g']} 
..  
..  
.. for k, v in x.items(): 
..     if k in y.keys(): 
..         y[k] += v 
..     else: 
..         y[k] = v 
..      
.. print y
{1: ['d', 'e', 'f', 'a', 'b', 'c'], 2: ['g'], 3: ['y']}

2
你可以这样做:
final = {}
dicts = [x,y]  # x and y are each dicts defined by op

for D in dicts:
    for key, value in D.items():  # in python 2 use D.iteritems() instead
        final[key] = final.get(key,[]).extend(value)

final.get(key,[])会获取final中对应键值的值,如果不存在,则返回一个空列表。 .extend(value)将扩展该列表(无论是否为空)与D中对应的值,此处为xy


应该是 D.iteritems() 吧? - gtangil
2
@gtangil:我认为这是Python 2与3之间的问题(您的建议是Python 2的方式)。 - El'endia Starman
@El'endiaStarman Python 2 使用 D.iteritems,但是 Python 3 需要使用 .items()。已编辑答案以反映此变化。 - fantabolous
1
final.get(key,[]) 不会返回一个空列表,它会返回一个 NoneType 并抛出一个错误。 - Mdev
@Mdev,extend总是返回None,因此最后一行是不正确的。应该是:final[key] = final.get(key, []) + value - Trody

1
这是对我有效的方法:

d1={'a':[1,2,3], 'b':[4,5,6], 'c':[7,8,9]}
d2 = {'a':[10,11,12], 'b':[13,14,15], 'c':[16,17,18]}
d3 = {}
for k in d1.keys():
    d3.update( {k : []} )
    for i in d1[k]:
        d3[k].append(i)
    for j in d2[k]:
        d3[k].append(j)
print(d3)

我知道这是一个绕路的方式,但是当字典值为ndarrays时,其他方法都不起作用。

0

这是一个针对任意数量字典的Python 3解决方案:

def dict_merge(*dicts_list):
    result = {}
    for d in dicts_list:
        for k, v in d.items():
            result.setdefault(k, []).append(v)
    return result

请注意,此解决方案可能会创建具有重复值的列表。如果您需要唯一值,请使用set()
def dict_merge(*dicts_list):
    result = {}
    for d in dicts_list:
        for k, v in d.items():
            result.setdefault(k, set()).add(v)
    return result

-2

如果您在项目中选择Python2.7。Counter() 可以在这种情况下使用:

Python 2.7.16 (default, Jun  5 2020, 22:59:21) 
[GCC 4.2.1 Compatible Apple LLVM 11.0.3 (clang-1103.0.29.20) (-macos10.15-objc- on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> x={1:['a','b','c']}
>>> y={1:['d','e','f'],2:['g']}
>>> from collections import Counter
>>> Counter(x) + Counter(y)
Counter({2: ['g'], 1: ['a', 'b', 'c', 'd', 'e', 'f']})

在Python 3.x中,如果您运行相同的代码,您将会看到:
Python 3.9.0 (v3.9.0:9cf6752276, Oct  5 2020, 11:29:23) 
Type 'copyright', 'credits' or 'license' for more information
IPython 7.19.0 -- An enhanced Interactive Python. Type '?' for help.

In [1]: x={1:['a','b','c']}

In [2]: y={1:['d','e','f'],2:['g']}

In [3]: from collections import Counter

In [4]: Counter(x) + Counter(y)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-4-0aa8b00837b3> in <module>
----> 1 Counter(x) + Counter(y)

/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/collections/__init__.py in __add__(self, other)
    759         for elem, count in self.items():
    760             newcount = count + other[elem]
--> 761             if newcount > 0:
    762                 result[elem] = newcount
    763         for elem, count in other.items():

TypeError: '>' not supported between instances of 'list' and 'int'

让我们来看一下源代码,位于vim /Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/collections/__init__.py +761

为了检查Python2.x和Python3.x之间的区别,我们将找到Python2.x中collections的路径。只需执行错误调用即可:

>>> Counter(9,1) # wrong way to call.
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/collections.py", line 475, in __init__
    raise TypeError('expected at most 1 arguments, got %d' % len(args))
TypeError: expected at most 1 arguments, got 2

然后,你会看到 /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/collections.py

好的,现在打开两个文件并定位到 class Counter 中的__add__函数。

vim -d /Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/collections/__init__.py +761 /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/collections.py

但是我们可以在这个代码片段中找到区别。

enter image description here

想一想,你可以看到TypeError: '>' not supported between instances of 'list' and 'int'显示了两个重要的事情:

  • >反映了class dict中的def __gt__(self, value, /)方法。所以让我们来检查一下Python2和Python3 dict之间的区别。
  • 'list''int'。为了确保我们在这里遇到相同的类型,只需添加一行代码将其打印出来。在执行比较行if newcount > 0:之前,像这样进行:
print("newcount is --> ", newcount, type(newcount))
if newcount > 0:

然后你会看到这个:

enter image description here

不意外,对吧?我们可以将listint进行比较,这是有道理的。

让我们快速比较一下Python 2中的listint

enter image description here 它返回了一个True。继续深入研究Python3.x。

enter image description here

好的,现在你应该清楚发生了什么。要解决这个问题,你可以轻松地对自己的Python环境进行一些更改或将其提交到git

enter image description here

最后,你得到了两个好消息,你修复了Python3.x的错误,并且获得了你的结果。

enter image description here

如果你想要的结果是一个字典,你可以使用以下方法:
z = dict(Counter(x) + Counter(y))

请注意,如果这些字典不相交(即:如果它们没有共同的元素),则此方法无效。 - gtangil
11
我收到了一个错误信息:>' not supported between instances of 'list' and 'int'。意思是在列表和整数之间无法使用 > 进行比较。 - Frank AK
1
@FrankAK 你能详细说明一下在什么情况下会出现这个错误吗? - nitishagar
@nitishagar已经更新了。感谢您的提醒。 - Frank AK

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接