如何在Python中区分两个词典?

时间:2015-09-28 04:20:32

标签: python

我有两本词典。我需要找到两者之间的区别,它应该给我关键和价值。

我搜索并发现了一些像datadiff,dictdiff-master这样的插件/软件包,但是当我在Python 2.7中尝试它时,它说没有定义这样的模块。

我在这里使用了set。

first_dict = {}
second_dict = {}

value = set(second_dict)-set(first_dict)
print value

输出>>>设置([' SCD-3547',' SCD-3456'])

我只得到钥匙,我甚至需要获得价值。

12 个答案:

答案 0 :(得分:45)

我认为最好使用集合的对称差分操作(https://docs.python.org/2/library/sets.html)。

>>> dict1 = {1:'donkey', 2:'chicken', 3:'dog'}
>>> dict2 = {1:'donkey', 2:'chimpansee', 4:'chicken'}
>>> set1 = set(dict1.items())
>>> set2 = set(dict2.items())
>>> set1 ^ set2
{(2, 'chimpansee'), (4, 'chicken'), (2, 'chicken'), (3, 'dog')}

它是对称的,因为:

>>> set2 ^ set1
{(2, 'chimpansee'), (4, 'chicken'), (2, 'chicken'), (3, 'dog')}

使用差异运算符时不是这种情况

>>> set1 - set2
{(2, 'chicken'), (3, 'dog')}
>>> set2 - set1
{(2, 'chimpansee'), (4, 'chicken')}

但是,将结果集转换为字典可能不是一个好主意,因为您可能会丢失信息:

>>> dict(set1 ^ set2)
{2: 'chicken', 3: 'dog', 4: 'chicken'}

答案 1 :(得分:38)

使用字典理解尝试以下代码段:

value = { k : second_dict[k] for k in set(second_dict) - set(first_dict) }

在上面的代码中,我们找到了的密钥,然后使用相应的值重建dict

答案 2 :(得分:6)

另一种解决方案是dictdifferhttps://github.com/inveniosoftware/dictdiffer)。

import dictdiffer                                          

a_dict = {                                                 
  'a': 'foo',
  'b': 'bar',
  'd': 'barfoo'
}                                                          

b_dict = {                                                 
  'a': 'foo',                                              
  'b': 'BAR',
  'c': 'foobar'
}                                                          

for diff in list(dictdiffer.diff(a_dict, b_dict)):         
    print diff

diff是一个元组,其中包含更改类型,更改的值以及条目的路径。

('change', 'b', ('bar', 'BAR'))
('add', '', [('c', 'foobar')])
('remove', '', [('d', 'barfoo')])

答案 3 :(得分:5)

你是正确的看待使用一套,我们只需要深入挖掘,让你的方法工作。

首先,示例代码:

test_1 = {"foo": "bar", "FOO": "BAR"}
test_2 = {"foo": "bar", "f00": "b@r"}

我们现在可以看到两个词典都包含类似的键/值对:

{"foo": "bar", ...}

每个字典还包含完全不同的键值对。但是我们如何发现差异呢?字典不支持这一点。相反,你想要使用一套。

以下是如何将每个字典转换为我们可以使用的集合:

set_1 = set(test_1.items())
set_2 = set(test_2.items())

这将返回包含一系列元组的集合。每个元组代表字典中的一个键/值对。

现在,找出set_1和set_2之间的区别:

print set_1 - set_2
>>> {('FOO', 'BAR')}

想要一本字典吗?简单,只是:

dict(set_1 - set_2)
>>> {'FOO': 'BAR'}

答案 4 :(得分:3)

此函数仅根据字典键为您提供所有差异(以及保持不变的差异)。它还突出了一些不错的Dict理解,Set操作和python 3.6类型注释:)

def get_dict_diffs(a: Dict[str, Any], b: Dict[str, Any]) -> Tuple[Dict[str, Any], Dict[str, Any], Dict[str, Any], Dict[str, Any]]:

    added_to_b_dict: Dict[str, Any] = {k: b[k] for k in set(b) - set(a)}
    removed_from_a_dict: Dict[str, Any] = {k: a[k] for k in set(a) - set(b)}
    common_dict_a: Dict[str, Any] = {k: a[k] for k in set(a) & set(b)}
    common_dict_b: Dict[str, Any] = {k: b[k] for k in set(a) & set(b)}
    return added_to_b_dict, removed_from_a_dict, common_dict_a, common_dict_b

如果您想比较词典

values_in_b_not_a_dict = {k : b[k] for k, _ in set(b.items()) - set(a.items())}

答案 5 :(得分:0)

这个怎么样?不是很漂亮而是明确。

orig_dict = {'a' : 1, 'b' : 2}
new_dict = {'a' : 2, 'v' : 'hello', 'b' : 2}

updates = {}
for k2, v2 in new_dict.items():
    if k2 in orig_dict:    
        if v2 != orig_dict[k2]:
            updates.update({k2 : v2})
    else:
        updates.update({k2 : v2})

#test it
#value of 'a' was changed
#'v' is a completely new entry
assert all(k in updates for k in ['a', 'v'])

答案 6 :(得分:0)

def flatten_it(d):
    if isinstance(d, list) or isinstance(d, tuple):
        return tuple([flatten_it(item) for item in d])
    elif isinstance(d, dict):
        return tuple([(flatten_it(k), flatten_it(v)) for k, v in sorted(d.items())])
    else:
        return d

dict1 = {'a': 1, 'b': 2, 'c': 3}
dict2 = {'a': 1, 'b': 1}

print set(flatten_it(dict1)) - set(flatten_it(dict2)) # set([('b', 2), ('c', 3)])
# or 
print set(flatten_it(dict2)) - set(flatten_it(dict1)) # set([('b', 1)])

答案 7 :(得分:0)

使用对称差集运算符的函数,如其他答案所述,该函数保留值的原点:

def diff_dicts(a, b, missing=KeyError):
    """
    Find keys and values which differ from `a` to `b` as a dict.

    If a value differs from `a` to `b` then the value in the returned dict will
    be: `(a_value, b_value)`. If either is missing then the token from 
    `missing` will be used instead.

    :param a: The from dict
    :param b: The to dict
    :param missing: A token used to indicate the dict did not include this key
    :return: A dict of keys to tuples with the matching value from a and b
    """
    return {
        key: (a.get(key, missing), b.get(key, missing))
        for key in dict(
            set(a.items()) ^ set(b.items())
        ).keys()
    }

示例

print(diff_dicts({'a': 1, 'b': 1}, {'b': 2, 'c': 2}))

# {'c': (<class 'KeyError'>, 2), 'a': (1, <class 'KeyError'>), 'b': (1, 2)}

这是如何工作的

我们对取物品产生的元组使用对称差集运算符。这会根据这两个字典生成一组不同的(key, value)元组。

然后我们据此做出新的决定,将密钥折叠在一起并对其进行迭代。这些是从一个字典更改为下一个字典的唯一键。

然后,当这些键不存在时,我们将使用这些键以及来自每个dict的值的元组代替丢失的令牌来组成一个新的dict。

答案 8 :(得分:0)

不确定这是 OP 要求的内容,但是当我遇到这个问题时,这就是我正在寻找的内容 - 具体来说,如何逐键显示两个字典之间的差异:

陷阱:当一个字典缺少键,而第二个字典有一个 None 值时,函数会假设它们是相似的

这根本没有优化 - 适用于小字典

def diff_dicts(a, b, drop_similar=True):
    res = a.copy()

    for k in res:
        if k not in b:
            res[k] = (res[k], None)

    for k in b:
        if k in res:
            res[k] = (res[k], b[k])
        else:
            res[k] = (None, b[k])

    if drop_similar:
        res = {k:v for k,v in res.items() if v[0] != v[1]}

    return res


print(diff_dicts({'a': 1}, {}))
print(diff_dicts({'a': 1}, {'a': 2}))
print(diff_dicts({'a': 2}, {'a': 2}))
print(diff_dicts({'a': 2}, {'b': 2}))
print(diff_dicts({'a': 2}, {'a': 2, 'b': 1}))

输出:

{'a': (1, None)}
{'a': (1, 2)}
{}
{'a': (2, None), 'b': (None, 2)}
{'b': (None, 1)}

答案 9 :(得分:0)

一个解决方案是使用 unittest 模块:

from unittest import TestCase
TestCase().assertDictEqual(expected_dict, actual_dict)

How can you test that two dictionaries are equal with pytest in python获得

答案 10 :(得分:-1)

老问题,但以为我还是会分享我的解决方案。很简单。

dicta_set = set(dicta.items()) # creates a set of tuples (k/v pairs)
dictb_set = set(dictb.items())
setdiff = dictb_set.difference(dicta_set) # any set method you want for comparisons
for k, v in setdiff: # unpack the tuples for processing
    print(f"k/v differences = {k}: {v}")

此代码创建代表k / v对的两组元组。然后,它使用您选择的set方法来比较元组。最后,它解压缩了元组(k / v对)以进行处理。

答案 11 :(得分:-1)

这将返回一个新的字典(仅更改数据)。

def get_difference(obj_1: dict, obj_2: dict) -> dict:
result = {}

for key in obj_1.keys():
    value = obj_1[key]

    if isinstance(value, dict):
        difference = get_difference(value, obj_2.get(key, {}))

        if difference:
            result[key] = difference

    elif value != obj_2.get(key):
        result[key] = obj_2.get(key, None)

return result