比较两个字典并检查有多少(键,值)对是相等的

我有两本字典,但为了简化起见,我就选这两本:

>>> x = dict(a=1, b=2)
>>> y = dict(a=2, b=2)

现在,我想比较x中的每个key, value对在y中是否有相同的对应值。所以我写了这个:

>>> for x_values, y_values in zip(x.iteritems(), y.iteritems()):
if x_values == y_values:
print 'Ok', x_values, y_values
else:
print 'Not', x_values, y_values

并且它工作,因为返回tuple,然后比较是否相等。

我的问题:

这对吗?是否有更好的方法来做到这一点?最好不是在速度上,我说的是代码优雅。

更新:我忘记提到我必须检查有多少key, value对是相等的。

775408 次浏览

你要做的只是x==y

你这样做不是一个好主意,因为字典里的条目不应该有任何顺序。你可能会比较[('a',1),('b',1)][('b',1), ('a',1)](相同的字典,不同的顺序)。

例如,看这个:

>>> x = dict(a=2, b=2,c=3, d=4)
>>> x
{'a': 2, 'c': 3, 'b': 2, 'd': 4}
>>> y = dict(b=2,c=3, d=4)
>>> y
{'c': 3, 'b': 2, 'd': 4}
>>> zip(x.iteritems(), y.iteritems())
[(('a', 2), ('c', 3)), (('c', 3), ('b', 2)), (('b', 2), ('d', 4))]

区别只是一项,但是你的算法会看到所有项是不同的

如果你想知道在两个字典中有多少值是匹配的,你应该这样说:)

也许是这样的:

shared_items = {k: x[k] for k in x if k in y and x[k] == y[k]}
print(len(shared_items))

我是python的新手,但我最终做了类似于@mouad的事情

unmatched_item = set(dict_1.items()) ^ set(dict_2.items())
len(unmatched_item) # should be 0

XOR操作符(^)应该在两个字典中相同的情况下消除字典中的所有元素。

def dict_compare(d1, d2):
d1_keys = set(d1.keys())
d2_keys = set(d2.keys())
shared_keys = d1_keys.intersection(d2_keys)
added = d1_keys - d2_keys
removed = d2_keys - d1_keys
modified = {o : (d1[o], d2[o]) for o in shared_keys if d1[o] != d2[o]}
same = set(o for o in shared_keys if d1[o] == d2[o])
return added, removed, modified, same


x = dict(a=1, b=2)
y = dict(a=2, b=2)
added, removed, modified, same = dict_compare(x, y)

@mouad的答案很好,如果你假设两个字典都只包含简单的值。然而,如果你有包含字典的字典,你会得到一个异常,因为字典是不可哈希的。

在我的脑海中,这样做可能有用:

def compare_dictionaries(dict1, dict2):
if dict1 is None or dict2 is None:
print('Nones')
return False


if (not isinstance(dict1, dict)) or (not isinstance(dict2, dict)):
print('Not dict')
return False


shared_keys = set(dict1.keys()) & set(dict2.keys())


if not ( len(shared_keys) == len(dict1.keys()) and len(shared_keys) == len(dict2.keys())):
print('Not all keys are shared')
return False




dicts_are_equal = True
for key in dict1.keys():
if isinstance(dict1[key], dict) or isinstance(dict2[key], dict):
dicts_are_equal = dicts_are_equal and compare_dictionaries(dict1[key], dict2[key])
else:
dicts_are_equal = dicts_are_equal and all(atleast_1d(dict1[key] == dict2[key]))


return dicts_are_equal
>>> hash_1
{'a': 'foo', 'b': 'bar'}
>>> hash_2
{'a': 'foo', 'b': 'bar'}
>>> set_1 = set (hash_1.iteritems())
>>> set_1
set([('a', 'foo'), ('b', 'bar')])
>>> set_2 = set (hash_2.iteritems())
>>> set_2
set([('a', 'foo'), ('b', 'bar')])
>>> len (set_1.difference(set_2))
0
>>> if (len(set_1.difference(set_2)) | len(set_2.difference(set_1))) == False:
...    print "The two hashes match."
...
The two hashes match.
>>> hash_2['c'] = 'baz'
>>> hash_2
{'a': 'foo', 'c': 'baz', 'b': 'bar'}
>>> if (len(set_1.difference(set_2)) | len(set_2.difference(set_1))) == False:
...     print "The two hashes match."
...
>>>
>>> hash_2.pop('c')
'baz'

这是另一个选择:

>>> id(hash_1)
140640738806240
>>> id(hash_2)
140640738994848

所以你可以看到这两个id是不同的。但是丰富的比较运算符似乎可以做到这一点:

>>> hash_1 == hash_2
True
>>>
>>> hash_2
{'a': 'foo', 'b': 'bar'}
>>> set_2 = set (hash_2.iteritems())
>>> if (len(set_1.difference(set_2)) | len(set_2.difference(set_1))) == False:
...     print "The two hashes match."
...
The two hashes match.
>>>

还有一种可能,直到OP的最后一个音符,是比较转储为JSON的字典的哈希值(SHAMD)。构造哈希的方式保证如果它们相等,源字符串也相等。这是非常快速和数学上合理的。

import json
import hashlib


def hash_dict(d):
return hashlib.sha1(json.dumps(d, sort_keys=True)).hexdigest()


x = dict(a=1, b=2)
y = dict(a=2, b=2)
z = dict(a=1, b=2)


print(hash_dict(x) == hash_dict(y))
print(hash_dict(x) == hash_dict(z))

只使用:

assert cmp(dict1, dict2) == 0
import json


if json.dumps(dict1) == json.dumps(dict2):
print("Equal")

dic1 == dic2

python文档:

下面的例子所有返回一个字典平等的 to {"one": 1, "two": 2, "three": 3}: < / p >
>>> a = dict(one=1, two=2, three=3)
>>> b = {'one': 1, 'two': 2, 'three': 3}
>>> c = dict(zip(['one', 'two', 'three'], [1, 2, 3]))
>>> d = dict([('two', 2), ('one', 1), ('three', 3)])
>>> e = dict({'three': 3, 'one': 1, 'two': 2})
>>> a == b == c == d == e
True

提供第一个例子中的关键字参数只适用于 是有效的Python标识符的键。否则,任何有效的密钥都可以 被使用。< / em > < / p >

比较对python2python3有效。

代码

def equal(a, b):
type_a = type(a)
type_b = type(b)
    

if type_a != type_b:
return False
    

if isinstance(a, dict):
if len(a) != len(b):
return False
for key in a:
if key not in b:
return False
if not equal(a[key], b[key]):
return False
return True


elif isinstance(a, list):
if len(a) != len(b):
return False
while len(a):
x = a.pop()
index = indexof(x, b)
if index == -1:
return False
del b[index]
return True
        

else:
return a == b


def indexof(x, a):
for i in range(len(a)):
if equal(x, a[i]):
return i
return -1

测试

>>> a = {
'number': 1,
'list': ['one', 'two']
}
>>> b = {
'list': ['two', 'one'],
'number': 1
}
>>> equal(a, b)
True

在PyUnit中有一个比较字典的方法。我使用以下两个字典对它进行了测试,它完全符合您的要求。

d1 = {1: "value1",
2: [{"subKey1":"subValue1",
"subKey2":"subValue2"}]}
d2 = {1: "value1",
2: [{"subKey2":"subValue2",
"subKey1": "subValue1"}]
}




def assertDictEqual(self, d1, d2, msg=None):
self.assertIsInstance(d1, dict, 'First argument is not a dictionary')
self.assertIsInstance(d2, dict, 'Second argument is not a dictionary')


if d1 != d2:
standardMsg = '%s != %s' % (safe_repr(d1, True), safe_repr(d2, True))
diff = ('\n' + '\n'.join(difflib.ndiff(
pprint.pformat(d1).splitlines(),
pprint.pformat(d2).splitlines())))
standardMsg = self._truncateMessage(standardMsg, diff)
self.fail(self._formatMessage(msg, standardMsg))

我不建议在你的生产代码中导入unittest。我的想法是,PyUnit中的源代码可以重新配置,以在生产环境中运行。它使用pprint来“漂亮地打印”字典。调整这段代码以使其“适合生产”似乎很容易。

在Python 3.6中,可以这样做:-

if (len(dict_1)==len(dict_2):
for i in dict_1.items():
ret=bool(i in dict_2.items())

如果dict_1中的所有项都出现在dict_2中,Ret变量将为真

see dictionary view objects: https://docs.python.org/2/library/stdtypes.html#dict < / p >

这样你可以从dictView1中减去dictView2,它将返回一组在dictView2中不同的键/值对:

original = {'one':1,'two':2,'ACTION':'ADD'}
originalView=original.viewitems()
updatedDict = {'one':1,'two':2,'ACTION':'REPLACE'}
updatedDictView=updatedDict.viewitems()
delta=original | updatedDict
print delta
>>set([('ACTION', 'REPLACE')])
你可以交叉,并,差(如上所示),对称差这些字典视图对象 更好吗?更快呢?-不确定,但标准库的一部分-这使得它的可移植性大大增加

测试两个字典的键和值是否相等:

def dicts_equal(d1,d2):
""" return True if all keys and values are the same """
return all(k in d2 and d1[k] == d2[k]
for k in d1) \
and all(k in d1 and d1[k] == d2[k]
for k in d2)

如果你想返回不同的值,请以不同的方式书写:

def dict1_minus_d2(d1, d2):
""" return the subset of d1 where the keys don't exist in d2 or
the values in d2 are different, as a dict """
return {k,v for k,v in d1.items() if k in d2 and v == d2[k]}

你必须调用它两次,即

dict1_minus_d2(d1,d2).extend(dict1_minus_d2(d2,d1))

功能很好IMO,清晰直观。但为了给你(另一个)答案,我是这么说的:

def compare_dict(dict1, dict2):
for x1 in dict1.keys():
z = dict1.get(x1) == dict2.get(x1)
if not z:
print('key', x1)
print('value A', dict1.get(x1), '\nvalue B', dict2.get(x1))
print('-----\n')

可能对你或任何人都有用。

编辑:

我已经创建了一个递归版本的上面..在其他答案中没有看到吗

def compare_dict(a, b):
# Compared two dictionaries..
# Posts things that are not equal..
res_compare = []
for k in set(list(a.keys()) + list(b.keys())):
if isinstance(a[k], dict):
z0 = compare_dict(a[k], b[k])
else:
z0 = a[k] == b[k]


z0_bool = np.all(z0)
res_compare.append(z0_bool)
if not z0_bool:
print(k, a[k], b[k])
return np.all(res_compare)

由于似乎没有人提到deepdiff,为了完整起见,我将在这里添加它。我发现它非常方便获得(嵌套)对象的差异:

安装

pip install deepdiff

示例代码

import deepdiff
import json


dict_1 = {
"a": 1,
"nested": {
"b": 1,
}
}


dict_2 = {
"a": 2,
"nested": {
"b": 2,
}
}


diff = deepdiff.DeepDiff(dict_1, dict_2)
print(json.dumps(diff, indent=4))

输出

{
"values_changed": {
"root['a']": {
"new_value": 2,
"old_value": 1
},
"root['nested']['b']": {
"new_value": 2,
"old_value": 1
}
}
}

注意关于检查结果的漂亮打印:如果两个字典具有相同的属性键(可能与示例中的属性值不同),上面的代码就可以工作。但是,如果存在"extra"属性是字典之一,则json.dumps()将失败

TypeError: Object of type PrettyOrderedSet is not JSON serializable

解决方案:使用diff.to_json()json.loads() / json.dumps()来漂亮地打印:

import deepdiff
import json


dict_1 = {
"a": 1,
"nested": {
"b": 1,
},
"extra": 3
}


dict_2 = {
"a": 2,
"nested": {
"b": 2,
}
}


diff = deepdiff.DeepDiff(dict_1, dict_2)
print(json.dumps(json.loads(diff.to_json()), indent=4))

输出:

{
"dictionary_item_removed": [
"root['extra']"
],
"values_changed": {
"root['a']": {
"new_value": 2,
"old_value": 1
},
"root['nested']['b']": {
"new_value": 2,
"old_value": 1
}
}
}

替代方法:使用pprint,结果是不同的格式:

import pprint


# same code as above


pprint.pprint(diff, indent=4)

输出:

{   'dictionary_item_removed': [root['extra']],
'values_changed': {   "root['a']": {   'new_value': 2,
'old_value': 1},
"root['nested']['b']": {   'new_value': 2,
'old_value': 1}}}

这是我的答案,使用递归的方式:

def dict_equals(da, db):
if not isinstance(da, dict) or not isinstance(db, dict):
return False
if len(da) != len(db):
return False
for da_key in da:
if da_key not in db:
return False
if not isinstance(db[da_key], type(da[da_key])):
return False
if isinstance(da[da_key], dict):
res = dict_equals(da[da_key], db[da_key])
if res is False:
return False
elif da[da_key] != db[da_key]:
return False
return True


a = {1:{2:3, 'name': 'cc', "dd": {3:4, 21:"nm"}}}
b = {1:{2:3, 'name': 'cc', "dd": {3:4, 21:"nm"}}}
print dict_equals(a, b)

希望有帮助!

下面的代码将帮助您比较python中的dict列表

def compate_generic_types(object1, object2):
if isinstance(object1, str) and isinstance(object2, str):
return object1 == object2
elif isinstance(object1, unicode) and isinstance(object2, unicode):
return object1 == object2
elif isinstance(object1, bool) and isinstance(object2, bool):
return object1 == object2
elif isinstance(object1, int) and isinstance(object2, int):
return object1 == object2
elif isinstance(object1, float) and isinstance(object2, float):
return object1 == object2
elif isinstance(object1, float) and isinstance(object2, int):
return object1 == float(object2)
elif isinstance(object1, int) and isinstance(object2, float):
return float(object1) == object2


return True


def deep_list_compare(object1, object2):
retval = True
count = len(object1)
object1 = sorted(object1)
object2 = sorted(object2)
for x in range(count):
if isinstance(object1[x], dict) and isinstance(object2[x], dict):
retval = deep_dict_compare(object1[x], object2[x])
if retval is False:
print "Unable to match [{0}] element in list".format(x)
return False
elif isinstance(object1[x], list) and isinstance(object2[x], list):
retval = deep_list_compare(object1[x], object2[x])
if retval is False:
print "Unable to match [{0}] element in list".format(x)
return False
else:
retval = compate_generic_types(object1[x], object2[x])
if retval is False:
print "Unable to match [{0}] element in list".format(x)
return False


return retval


def deep_dict_compare(object1, object2):
retval = True


if len(object1) != len(object2):
return False


for k in object1.iterkeys():
obj1 = object1[k]
obj2 = object2[k]
if isinstance(obj1, list) and isinstance(obj2, list):
retval = deep_list_compare(obj1, obj2)
if retval is False:
print "Unable to match [{0}]".format(k)
return False


elif isinstance(obj1, dict) and isinstance(obj2, dict):
retval = deep_dict_compare(obj1, obj2)
if retval is False:
print "Unable to match [{0}]".format(k)
return False
else:
retval = compate_generic_types(obj1, obj2)
if retval is False:
print "Unable to match [{0}]".format(k)
return False


return retval

迟回复总比不回复好!

比较Not_Equal比比较Equal更有效。因此,如果一个字典中的任何键值在另一个字典中找不到,那么两个字典就不相等。下面的代码考虑到您可能比较默认的dict,因此使用get而不是getitem[]。

在get调用中使用一种随机值作为默认值,等于要检索的键-以防dicts在一个dict中有None作为值,而该键在另一个dict中不存在。此外,为了提高效率,get !=条件是在not in条件之前检查的,因为您同时对两边的键和值进行检查。

def Dicts_Not_Equal(first,second):
""" return True if both do not have same length or if any keys and values are not the same """
if len(first) == len(second):
for k in first:
if first.get(k) != second.get(k,k) or k not in second: return (True)
for k in second:
if first.get(k,k) != second.get(k) or k not in first: return (True)
return (False)
return (True)

我正在使用这个解决方案,在Python 3中完美地为我工作


import logging
log = logging.getLogger(__name__)


...


def deep_compare(self,left, right, level=0):
if type(left) != type(right):
log.info("Exit 1 - Different types")
return False


elif type(left) is dict:
# Dict comparison
for key in left:
if key not in right:
log.info("Exit 2 - missing {} in right".format(key))
return False
else:
if not deep_compare(left[str(key)], right[str(key)], level +1 ):
log.info("Exit 3 - different children")
return False
return True
elif type(left) is list:
# List comparison
for key in left:
if key not in right:
log.info("Exit 4 - missing {} in right".format(key))
return False
else:
if not deep_compare(left[left.index(key)], right[right.index(key)], level +1 ):
log.info("Exit 5 - different children")
return False
return True
else:
# Other comparison
return left == right


return False


它比较dict、list和其他单独实现"=="操作符的类型。 如果你需要比较其他不同的东西,你需要在“If树”中添加一个新的分支

希望这能有所帮助。

>>> x = {'a':1,'b':2,'c':3}
>>> x
{'a': 1, 'b': 2, 'c': 3}


>>> y = {'a':2,'b':4,'c':3}
>>> y
{'a': 2, 'b': 4, 'c': 3}


METHOD 1:


>>> common_item = x.items()&y.items() #using union,x.item()
>>> common_item
{('c', 3)}


METHOD 2:


>>> for i in x.items():
if i in y.items():
print('true')
else:
print('false')




false
false
true

python3:

data_set_a = dict_a.items()
data_set_b = dict_b.items()


difference_set = data_set_a ^ data_set_b

现在简单的比较==就足够了(python 3.8)。即使当你以不同的顺序比较相同的字典(上一个例子)。最好的是,您不需要第三方包来完成此任务。

a = {'one': 'dog', 'two': 'cat', 'three': 'mouse'}
b = {'one': 'dog', 'two': 'cat', 'three': 'mouse'}


c = {'one': 'dog', 'two': 'cat', 'three': 'mouse'}
d = {'one': 'dog', 'two': 'cat', 'three': 'mouse', 'four': 'fish'}


e = {'one': 'cat', 'two': 'dog', 'three': 'mouse'}
f = {'one': 'dog', 'two': 'cat', 'three': 'mouse'}


g = {'two': 'cat', 'one': 'dog', 'three': 'mouse'}
h = {'one': 'dog', 'two': 'cat', 'three': 'mouse'}




print(a == b) # True
print(c == d) # False
print(e == f) # False
print(g == h) # True

为什么不只是遍历一个字典,并在过程中检查另一个字典(假设两个字典都有相同的键)?

x = dict(a=1, b=2)
y = dict(a=2, b=2)


for key, val in x.items():
if val == y[key]:
print ('Ok', val, y[key])
else:
print ('Not', val, y[key])

输出:

Not 1 2
Ok 2 2

对两个字典进行深度比较的最简单的方法(也是最健壮的方法之一)是将它们序列化为JSON格式,对键进行排序,并比较字符串结果:

import json
if json.dumps(x, sort_keys=True) == json.dumps(y, sort_keys=True):
... Do something ...

你可以用下面的方法写出你自己的函数。

class Solution:
def find_if_dict_equal(self,dict1,dict2):
dict1_keys=list(dict1.keys())
dict2_keys=list(dict2.keys())
if len(dict1_keys)!=len(dict2_keys):
return False
for i in dict1_keys:
if i not in dict2 or dict2[i]!=dict1[i]:
return False
return True
        

def findAnagrams(self, s, p):
if len(s)<len(p):
return []
p_dict={}
for i in p:
if i not in p_dict:
p_dict[i]=0
p_dict[i]+=1
s_dict={}
final_list=[]
for i in s[:len(p)]:
if i not in s_dict:
s_dict[i]=0
s_dict[i]+=1
if self.find_if_dict_equal(s_dict,p_dict):
final_list.append(0)
for i in range(len(p),len(s)):
element_to_add=s[i]
element_to_remove=s[i-len(p)]
if element_to_add not in s_dict:
s_dict[element_to_add]=0
s_dict[element_to_add]+=1
s_dict[element_to_remove]-=1
if s_dict[element_to_remove]==0:
del s_dict[element_to_remove]
if self.find_if_dict_equal(s_dict,p_dict):
final_list.append(i-len(p)+1)
return final_list

我有一个默认/模板字典,我想从第二个给定的字典更新它的值。因此,更新将发生在默认字典中存在的键以及相关值与默认键/值类型兼容的键上。

在某种程度上,这与上面的问题类似。

我写下了这个解:

代码

def compDict(gDict, dDict):


gDictKeys = list(gDict.keys())
    

for gDictKey in gDictKeys:
try:
dDict[gDictKey]
except KeyError:
# Do the operation you wanted to do for "key not present in dict".
print(f'\nkey \'{gDictKey}\' does not exist! Dictionary key/value no set !!!\n')
else:
# check on type
if type(gDict[gDictKey]) == type(dDict[gDictKey]):
if type(dDict[gDictKey])==dict:
compDict(gDict[gDictKey],dDict[gDictKey])
else:
dDict[gDictKey] = gDict[gDictKey]
print('\n',dDict, 'update successful !!!\n')
else:
print(f'\nValue \'{gDict[gDictKey]}\' for \'{gDictKey}\' not a compatible data type !!!\n')
            



# default dictionary
dDict = {'A':str(),
'B':{'Ba':int(),'Bb':float()},
'C':list(),
}


# given dictionary
gDict = {'A':1234, 'a':'addio', 'C':['HELLO'], 'B':{'Ba':3,'Bb':'wrong'}}


compDict(gDict, dDict)


print('Updated default dictionry: ',dDict)

输出

“A”的值“1234”不是兼容的数据类型!!

键“a”不存在!字典键/值没有设置!!

{A: ", " B ":{“Ba”:0,“Bb”:0.0},“C”:['你好']}更新成功! !

{'Ba': 3, 'Bb': 0.0}更新成功!!

“Bb”的值“错误”不是兼容的数据类型!!

更新默认dictionry: {A:“B:{“Ba”:3,“Bb”:0.0},“C”:['你好']}