如何为相同的字典生成唯一的相等哈希?

时间:2013-05-24 13:11:09

标签: python

例如:

>>> a = {'req_params': {'app': '12345', 'format': 'json'}, 'url_params': {'namespace': 'foo', 'id': 'baar'}, 'url_id': 'rest'}
>>> b = {'req_params': { 'format': 'json','app': '12345' }, 'url_params': { 'id': 'baar' ,'namespace':'foo' }, 'url_id': 'REST'.lower() }
>>> a == b
 True

为两个dicts生成相等哈希值的好哈希函数是什么? 字典会 有基本数据类型,如int,list,dict和strings,没有其他对象。

如果散列是空间优化的,那将是很好的,目标集大约是500万个对象,因此碰撞机会相当少。

我不确定json.dumps或其他序列化是否支持相等而不是字典中成员的结构。 例如。使用str的dict进行基本哈希不起作用:

>>> a = {'name':'Jon','class':'nine'}
>>> b = {'class':'NINE'.lower(),'name':'Jon'}
>>> str(a)
"{'name': 'Jon', 'class': 'nine'}"
>>> str(b)
"{'class': 'nine', 'name': 'Jon'}"

json.dumps也不起作用:

>>> import json,hashlib
>>> a = {'name':'Jon','class':'nine'}
>>> b = {'class':'NINE'.lower(),'name':'Jon'}
>>> a == b
True
>>> ha = hashlib.sha256(json.dumps(a)).hexdigest()
>>> hb = hashlib.sha256(json.dumps(b)).hexdigest()
>>> ha
'545af862cc4d2dd1926fe0aa1e34ad5c3e8a319461941b33a47a4de9dbd7b5e3'
>>> hb 
'4c7d8dbbe1f180c7367426d631410a175d47fff329d2494d80a650dde7bed5cb'

4 个答案:

答案 0 :(得分:11)

pprint模块对dict键进行排序

from pprint import pformat
hash(pformat(a)) == hash(pformat(b))

如果要保留哈希值,则应使用hashlib中的哈希值。 sha1很多

答案 1 :(得分:1)

为什么不在散列之前进行排序?当然,它可能需要不可忽略的时间来完成它,但至少你可以继续使用“好的”散列函数,即显示良好色散加上所有其他所需属性的散列函数。此外,如果想要节省空间,可能是因为你期望字典中有很多条目,因此,当使用“好”散列函数时,通过不对字符串进行排序而节省的时间肯定会受到使用时的查找时间的支配。由于大量冲突导致的“坏”散列函数。

答案 2 :(得分:0)

不确定这是否是您想要的:

import json
import hashlib

a = # as above
b = # as above
c = {'req_params': {'app': '12345', 'format': 'json'},
  'url_params': {'id':'baar', 'namespace': 'foo' }, 'url_id': 'rest'}
d = {'url_params': {'id':'baar', 'namespace': 'foo' },
  'req_params': {'app': '12345', 'format': 'json'}, 'url_id': 'rest'}

ha = hashlib.sha256(json.dumps(a)).hexdigest()
hb = hashlib.sha256(json.dumps(b)).hexdigest()
hc = hashlib.sha256(json.dumps(c)).hexdigest()
hd = hashlib.sha256(json.dumps(d)).hexdigest()

assert ha == hb
assert ha == hc
assert ha == hd

答案 3 :(得分:0)

您还可以执行已排序字符串的哈希:

>>> a = {'name':'Jon','class':'nine'}
>>> b = {'class':'NINE'.lower(),'name':'Jon'}
>>> def isdeq(d1,d2):
...    def dhash(d):
...       return hash(str({k:d[k] for k in sorted(d)}))
...    return dhash(d1)==dhash(d2)
... 
>>> isdeq(a,b)
True
>>> isdeq({'name':'Jon','class':'nine'},{'name':'jon','class':'nine'})
False
>>> isdeq({'name':'Jon','class':'nine'},{'class':'nine','name':'Jon'})
True