如何在Python中合并和正确更新字典(其中值为列表)?

3

假设我有两个字典,其中值是列表(或集合也可以,因为内容是唯一的)。例如:

dic1 = {'math': ['algebra', 'trigonometry', 'geometry']}
dic2 = {'math': ['calculus'], 'science': ['physics']}
dic2.update(dic1)

我的期望输出应该是这样的:

{'math': ['algebra', 'trigonometry', 'geometry', 'calculus'], 'science': ['physics']}

但是我得到的却是:
{'math': ['algebra', 'trigonometry', 'geometry'], 'science': ['physics']}

在合并两个字典时,我希望将内容组合在一起(不想覆盖而是保留两者)。有没有简单的方法可以做到这一点?注意:在这个例子中,只有两个字典。虽然我还没写代码,但最终我想要循环遍历多个字典并在循环中执行此合并/更新的过程,这可能有助于提出一种方法。


可以假设dic1不会有dic2没有的键吗?如果是这样,那么 dic3 = {k: v + dic1.get(k, list()) for k, v in dic2.items()} - Cory Madden
这是一个好问题!谢谢你的提问。不,dic1和dic2可能会共享相同的键,就像上面的例子中共享“math”一样。 - Jane Sully
对不起,我的意思不是那个。我是指 dic1 仅包含 dic2 中存在的键。我觉得我表达得有些奇怪。 - Cory Madden
我更新了我的答案,以反映如果是这种情况,您如何确保这不是一个问题。 - Cory Madden
6个回答

2
这可以用一个简单的一行代码来表达:
>>> {k: dic1.get(k, []) + dic2.get(k, []) for k in (set(dic1) | set(dic2))}
{'science': ['physics'], 'math': ['algebra', 'trigonometry', 'geometry', 'calculus']}

这结合了三个技巧: Python 的核心工具包经常提供基本的数据操作问题的优雅解决方案。我经常惊讶于这些工具如何完美地组合在一起。
这如何帮助 :-)

1

如果您要合并多个列表字典以避免重复:

def updateDict(dict1, dict2):
   for key in dict1:
      if key in dict2:
         prev_values = set(dict1[key]) # create set to retain only unique values in list
         prev_values.update(dict2[key])
         dict1[key] = list(prev_values)

0
dict1 = {'math': ['algebra', 'trigonometry', 'geometry']}
dict2 = {'math': ['calclus'], 'science': ['physics']}
for key, value in dict1.items():
    dict2.setdefault(key, []).extend(value)

>>> print(dict2)
{'science': ['physics'], 'math': ['calclus', 'algebra', 'trigonometry', 'geometry']}

如果您想保留两个字典值,请执行以下操作

from copy import deepcopy

dict1 = {'math': ['algebra', 'trigonometry', 'geometry']}
dict2 = {'math': ['calclus'], 'science': ['physics'], 'lol':['lol1']}
dict3 = deepcopy(dict2)
for key, value in dict1.items():
    dict3.setdefault(key, []).extend(value)

>>>print(dict2)
{'science': ['physics'], 'math': ['calclus']}
>>>print(dict3)
{'science': ['physics'], 'math': ['calclus', 'algebra', 'trigonometry', 'geometry']}

0
这是一个字典推导式,如果 dic1 中不包含不在 dic2 中的键,则可以正常工作:
dic3 = {k: v + dic1.get(k, list()) for k, v in dic2.items()}

此外,为了确保将dic1中缺失的任何键添加到字典中,您可以在此之后添加一个for循环。
for k, v in dic1.items():
    if k not in dic3:
        dic3.update({k: v})

0

不知道有直接的方法,但这应该可以工作:

def combine_dicts(dict1,dict2):
    dict = {}
    for key1,list1 in dict1.items():
        for key2,list2 in dict2.items():
           if key1 == key2:
               dict[key1] = list1.extend(list2)
    return dict

0
你可以创建自己的字典类来获得所需的行为。我不确定什么是最好的方法,但这里有一个可能性:
import collections

class ListDict(collections.UserDict):
    def update(self, other):
        if isinstance(other, collections.Mapping):
            for key, value in other.items():
                self.data.setdefault(key, []).extend(value)
        else:
            raise NotImplementedError()

dic1 = ListDict({'math': ['algebra', 'trigonometry', 'geometry']})
dic2 = ListDict({'math': ['calculus'], 'science': ['physics']})
dic2.update(dic1)
print(dic2)

输出:

{'math': ['calculus', 'algebra', 'trigonometry', 'geometry'], 'science': ['physics']}

请注意,这只是实现所需行为的开始。根据您使用它的目的,您可能需要添加更多功能。例如,只有调用update的方法之一被实现。
为了防止结果集合中出现重复值,您可能希望改用集合:
import collections

class SetDict(collections.UserDict):
    def update(self, other):
        if isinstance(other, collections.Mapping):
            for key, value in other.items():
                self.data[key] = self.data.get(key, set()).union(value)
        else:
            raise NotImplementedError()

dic3 = SetDict({'math': ['algebra', 'trigonometry']})  # may contain lists ...
dic4 = SetDict({'math': {'algebra', 'geometry'}})  # ... or sets
dic4.update(dic3)
print(dic4)

输出:

{'math': {'algebra', 'geometry', 'trigonometry'}}

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