我有两本词典.我需要找到两者之间的区别,它应该给我关键和价值.
我搜索并发现了一些像datadiff,dictdiff-master这样的插件/软件包,但是当我在Python 2.7中尝试它时,它说没有定义这样的模块.
我在这里使用了set.
first_dict = {}
second_dict = {}
value = set(second_dict)-set(first_dict)
print value
Run Code Online (Sandbox Code Playgroud)
输出>>>设置(['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')}
Run Code Online (Sandbox Code Playgroud)
它是对称的,因为:
>>> set2 ^ set1
{(2, 'chimpansee'), (4, 'chicken'), (2, 'chicken'), (3, 'dog')}
Run Code Online (Sandbox Code Playgroud)
使用差异运算符时不是这种情况
>>> set1 - set2
{(2, 'chicken'), (3, 'dog')}
>>> set2 - set1
{(2, 'chimpansee'), (4, 'chicken')}
Run Code Online (Sandbox Code Playgroud)
但是,将结果集转换为字典可能不是一个好主意,因为您可能会丢失信息:
>>> dict(set1 ^ set2)
{2: 'chicken', 3: 'dog', 4: 'chicken'}
Run Code Online (Sandbox Code Playgroud)
Ósc*_*pez 52
使用字典理解尝试以下代码段:
value = { k : second_dict[k] for k in set(second_dict) - set(first_dict) }
Run Code Online (Sandbox Code Playgroud)
在上面的代码中,我们找到了键的差异,然后重建一个dict取相应的值.
Peq*_*que 21
您可以使用DeepDiff:
pip install deepdiff
Run Code Online (Sandbox Code Playgroud)
除此之外,它还允许您递归计算字典、可迭代对象、字符串和其他对象的差异:
pip install deepdiff
Run Code Online (Sandbox Code Playgroud)
它可以让您查看更改的内容(甚至类型)、添加的内容和删除的内容。它还允许您执行许多其他操作,例如忽略重复项和忽略路径(由正则表达式定义)。
Bra*_*ess 17
解决方案是使用该unittest模块:
from unittest import TestCase
TestCase().assertDictEqual(expected_dict, actual_dict)
Run Code Online (Sandbox Code Playgroud)
获取自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
Run Code Online (Sandbox Code Playgroud)
diff是一个元组,具有更改类型,更改的值和条目的路径.
('change', 'b', ('bar', 'BAR'))
('add', '', [('c', 'foobar')])
('remove', '', [('d', 'barfoo')])
Run Code Online (Sandbox Code Playgroud)
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)))
Run Code Online (Sandbox Code Playgroud)
输出是:
Left contains 1 more item:
{'a': 'b'}
Right contains 1 more item:
{'aa': 'vv'}
Full diff:
- {'aa': 'vv'}
? - ^^
+ {'a': 'b'}
? ^
Run Code Online (Sandbox Code Playgroud)
如果您不喜欢使用私有函数(以 开头_),只需查看源代码并将函数复制/粘贴到您的代码中。
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
Run Code Online (Sandbox Code Playgroud)
正如其他答案中提到的,使用对称差分集运算符的函数,它保留了值的起源:
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()
}
Run Code Online (Sandbox Code Playgroud)
print(diff_dicts({'a': 1, 'b': 1}, {'b': 2, 'c': 2}))
# {'c': (<class 'KeyError'>, 2), 'a': (1, <class 'KeyError'>), 'b': (1, 2)}
Run Code Online (Sandbox Code Playgroud)
我们对从项目生成的元组使用对称差分集运算符。这会(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}))
Run Code Online (Sandbox Code Playgroud)
输出:
{'a': (1, None)}
{'a': (1, 2)}
{}
{'a': (2, None), 'b': (None, 2)}
{'b': (None, 1)}
Run Code Online (Sandbox Code Playgroud)
你是正确的看待使用一套,我们只需要深入挖掘,让你的方法工作.
一,示例代码:
test_1 = {"foo": "bar", "FOO": "BAR"}
test_2 = {"foo": "bar", "f00": "b@r"}
Run Code Online (Sandbox Code Playgroud)
我们现在可以看到两个词典都包含类似的键/值对:
{"foo": "bar", ...}
Run Code Online (Sandbox Code Playgroud)
每个字典还包含完全不同的键值对.但我们如何发现差异呢?字典不支持这一点.相反,你会想要使用一套.
以下是如何将每个字典转换为我们可以使用的集合:
set_1 = set(test_1.items())
set_2 = set(test_2.items())
Run Code Online (Sandbox Code Playgroud)
这将返回包含一系列元组的集合.每个元组代表字典中的一个键/值对.
现在,要找到set_1和set_2之间的区别:
print set_1 - set_2
>>> {('FOO', 'BAR')}
Run Code Online (Sandbox Code Playgroud)
想要一本字典吗?简单,只需:
dict(set_1 - set_2)
>>> {'FOO': 'BAR'}
Run Code Online (Sandbox Code Playgroud)
此函数仅根据字典键为您提供所有差异(以及保持不变的差异)。它还强调了一些不错的 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
Run Code Online (Sandbox Code Playgroud)
如果要比较字典值:
values_in_b_not_a_dict = {k : b[k] for k, _ in set(b.items()) - set(a.items())}
Run Code Online (Sandbox Code Playgroud)
小智 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'])
Run Code Online (Sandbox Code Playgroud)
小智 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)])
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
61939 次 |
| 最近记录: |