比较Python中的两个字典
我有两本字典,但是为了简化,我会拿这两本:
>>> x = dict(a=1, b=2) >>> y = dict(a=2, b=2)
现在,我想比较x
中的每个key, value
对在x
是否具有相同的对应值。 所以我写了这个:
>>> 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
返回,然后比较平等。
我的问题:
它是否正确? 有没有更好的方法来做到这一点? 最好不要速度,我说的是代码优雅。
更新:我忘了提及,我必须检查有多less个key, value
对是相等的。
如果你想知道在这两个字典中有多less值匹配,你应该说:)
也许这样的事情:
shared_items = set(x.items()) & set(y.items()) print len(shared_items)
你想要做的只是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))]
差别只是一个项目,但是你的algorithm会看到所有的项目都是不同的
def dict_compare(d1, d2): d1_keys = set(d1.keys()) d2_keys = set(d2.keys()) intersect_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 intersect_keys if d1[o] != d2[o]} same = set(o for o in intersect_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)
我是新来的python,但我最终做了类似于@mouad
unmatched_item = set(dict_1.items()) ^ set(dict_2.items()) len(unmatched_item) # should be 0
XOR运算符( ^
)应该消除字典中的所有元素,当它们在两个字典中是相同的。
只要使用:
assert cmp(dict1, dict2) == 0
要检查两个字典是否有相同的内容,只需使用:
dic1 == dic2
@mouad的答案很好,如果你假设这两个字典只包含简单的值。 但是,如果你有包含字典的字典,你将会得到一个例外,因为字典是不可散列的。
我的头顶上,这样的东西可能会工作:
def compare_dictionaries(dict1, dict2): if dict1 == None or dict2 == None: return False if type(dict1) is not dict or type(dict2) is not dict: return False shared_keys = set(dict2.keys()) & set(dict2.keys()) if not ( len(shared_keys) == len(dict1.keys()) and len(shared_keys) == len(dict2.keys())): return False dicts_are_equal = True for key in dict1.keys(): if type(dict1[key]) is dict: dicts_are_equal = dicts_are_equal and compare_dictionaries(dict1[key],dict2[key]) else: dicts_are_equal = dicts_are_equal and (dict1[key] == dict2[key]) return dicts_are_equal
请注意,我对线路还不满意:
dicts_are_equal = dicts_are_equal and (dict1[key] == dict2[key])
因为这些值可能是对象。 能够检查两个对象是否实现可比较的接口将是很好的。
直到OP的最后一个注释还有另一种可能性,就是比较被转储为JSON的字符的散列( SHA
或MD
)。 构build哈希的方式保证了如果相等,源string也是相同的。 这是非常快速和math上的声音。
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))
码
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
testing
>>> a = { 'number': 1, 'list': ['one', 'two'] } >>> b = { 'list': ['two', 'one'], 'number': 1 } >>> equal(a, b) True
要testing两个字典在键和值上是否相等:
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))
>>> 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'
这是另一个select:
>>> 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. >>>
在PyUnit中有一种比较字典的方法。 我使用下面的两个字典对它进行了testing,它完全符合你的要求。
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))
我不build议将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_2中存在dict_1的所有项目,则retvariables将为true
请参阅字典视图对象: https : //docs.python.org/2/library/stdtypes.html#dict
这样你可以从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')])
你可以相交,联合,区别(如上所示),对称差异这些字典视图对象。
更好? 更快? – 不确定,但是标准库的一部分 – 这使得它成为便携性的一大优点
import json if json.dumps(dict1) == json.dumps(dict2): print("Equal")