我有两本词典.我需要找到两者之间的区别,它应该给我关键和价值.
我搜索并发现了一些像datadiff,dictdiff-master这样的插件/软件包,但是当我在Python 2.7中尝试它时,它说没有定义这样的模块.
我在这里使用了set.
first_dict = {}
second_dict = {}
value = set(second_dict)-set(first_dict)
print value
输出>>>设置(['SCD-3547','SCD-3456'])
我只获得关键,我甚至需要获得价值.
小智 59
我认为使用集合的对称差分操作更好(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'}
Ósc*_*pez 52
使用字典理解尝试以下代码段:
value = { k : second_dict[k] for k in set(second_dict) - set(first_dict) }
在上面的代码中,我们找到了键的差异,然后重建一个dict取相应的值.
Peq*_*que 21
您可以使用DeepDiff:
pip install deepdiff
除此之外,它还允许您递归计算字典、可迭代对象、字符串和其他对象的差异:
pip install deepdiff
它可以让您查看更改的内容(甚至类型)、添加的内容和删除的内容。它还允许您执行许多其他操作,例如忽略重复项和忽略路径(由正则表达式定义)。
Bra*_*ess 17
解决方案是使用该unittest模块:
from unittest import TestCase
TestCase().assertDictEqual(expected_dict, actual_dict)
获取自How can you test that two dictionaries are equal with pytest in python
Chr*_*ndt 13
另一个解决方案是dictdiffer(https://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')])
mrv*_*vol 11
我建议使用优秀开发人员已经编写的东西。喜欢pytest。它可以处理任何数据类型,而不仅仅是字典。而且,顺便说一句,pytest他非常擅长测试。
from _pytest.assertion.util import _compare_eq_any
print('\n'.join(_compare_eq_any({'a': 'b'}, {'aa': 'vv'}, verbose=3)))
输出是:
Left contains 1 more item:
{'a': 'b'}
Right contains 1 more item:
{'aa': 'vv'}
Full diff:
- {'aa': 'vv'}
?    -    ^^
+ {'a': 'b'}
?        ^
如果您不喜欢使用私有函数(以 开头_),只需查看源代码并将函数复制/粘贴到您的代码中。
PS:测试过pytest==6.2.4
这是我自己的版本,将/sf/answers/4708418361/与/sf/answers/3398111601/结合起来,现在我发现它与https://stackoverflow非常相似.com/a/47433207/919692:
def dict_diff(dict_a, dict_b, show_value_diff=True):
  result = {}
  result['added']   = {k: dict_b[k] for k in set(dict_b) - set(dict_a)}
  result['removed'] = {k: dict_a[k] for k in set(dict_a) - set(dict_b)}
  if show_value_diff:
    common_keys =  set(dict_a) & set(dict_b)
    result['value_diffs'] = {
      k:(dict_a[k], dict_b[k])
      for k in common_keys
      if dict_a[k] != dict_b[k]
    }
  return result
正如其他答案中提到的,使用对称差分集运算符的函数,它保留了值的起源:
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)根据两个字典生成一组不同的元组。
然后,我们从中创建一个新的字典,将键折叠在一起并迭代它们。这些是唯一从一个字典更改为下一个字典的键。
然后,我们使用这些键组成一个新的字典,其中每个字典中的值的元组在键不存在时替换我们丢失的标记。
不确定这是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)}
你是正确的看待使用一套,我们只需要深入挖掘,让你的方法工作.
一,示例代码:
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'}
此函数仅根据字典键为您提供所有差异(以及保持不变的差异)。它还强调了一些不错的 Dict 理解、集合操作和 python 3.6 类型注释:)
from typing import Dict, Any, Tuple
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
那这个呢?不那么漂亮但很明确。
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'])
小智 5
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)])
| 归档时间: | 
 | 
| 查看次数: | 61939 次 | 
| 最近记录: |