【问题标题】:How to generate unique equal hash for equal dictionaries?如何为相等的字典生成唯一的相等哈希?
【发布时间】:2013-05-24 22:39:56
【问题描述】:

例如:

>>> 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

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

如果散列是空间优化的,那就太好了,目标集大约是 500 万个对象,因此碰撞机会要少得多。

我不确定 json.dumps 或其他序列化是否尊重平等而不是字典中成员的结构。 例如。使用 dict 的 str 的基本散列不起作用:

>>> 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'

【问题讨论】:

  • 散列字符串化的字典?不知道这是否能保证平等......例如如果它的键(以及它的键的值的键等)将被打印排序
  • 确实,打印 dict 似乎是以某种方式打印的(但不确定如何)
  • @njzk2 我猜这个顺序是不确定的,
  • 有趣,显然它是平台相关的

标签: python


【解决方案1】:

pprint 模块对字典键进行排序

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

如果你想持久化哈希值,你应该使用 hashlib 中的哈希值。 sha1就够了

【讨论】:

  • 这是一个不错的技巧。谢谢。
【解决方案2】:

为什么不在散列之前排序?当然,它可能需要不可忽略的时间来完成,但至少你可以继续使用“好的”散列函数,即一个显示出良好分散性以及所有其他所需属性的散列函数。此外,如果这个想法是为了节省空间,那可能是因为您希望字典中有很多条目,因此,使用“好”散列函数时不对集合进行排序所节省的时间肯定会受到使用散列函数时的查找时间的支配。大量冲突导致的“坏”哈希函数。

【讨论】:

    【解决方案3】:

    不确定这是不是你想要的:

    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
    

    【讨论】:

    • 请查看我有问题的更新。它有时可能有效,但并非一直有效。
    • 很好,但是如果插入顺序不同,它会给出不同的结果。他可以使用repr() 代替json.dumps() 并预先对字典进行排序。
    • 正确,json.dumps 不保证订单。
    • json.dumps(x, sort_keys=True) 保证订单,不是吗?
    • 我和 Tommi 在一起,json.dumps(x, sort_keys=True) 不能解决这个问题吗?
    【解决方案4】:

    您还可以对已排序的字符串进行哈希处理:

    >>> 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
    

    【讨论】:

      猜你喜欢
      • 2013-09-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-02-12
      • 2011-10-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多