【问题标题】:dict_values intersection and hashable typesdict_values 交集和可散列类型
【发布时间】:2020-03-20 17:24:15
【问题描述】:

我想检查两个字典的交集。如果我这样做,我会得到我所期望的:

dict1 = {'x':1, 'y':2, 'z':3}
dict2 = {'x':1, 'y':2, 'z':4}

set(dict1.items()).intersection(dict2.items())
>> {('x', 1), ('y', 2)}

但是,如果字典中的项目 是不可散列的,则会出现错误。

dict1 = {'x':{1,2}, 'y':{2,3}, 'z':3}
dict2 = {'x':{1,3}, 'y':{2,4}, 'z':4}  

TypeError                                 Traceback (most recent call 
last)
<ipython-input-56-33fdb931ef54> in <module>
 ----> 1 set(dict1.items()).intersection(dict2.items())

TypeError: unhashable type: 'set'

当然,对于元组和列表,我也会遇到同样的错误,因为它们也不是可散列的。

是否有解决方法或现有类可用于检查不可散列字典值的交集?

【问题讨论】:

  • x y 和 z 代表某种点?
  • 不,这只是代表性数据。实际情况完全不同,但没关系,对吧?
  • @Prune 您链接到的问题不是针对不可散列的 dict 值,这是 OP 特别想要解决的问题。
  • 接受的答案是针对可散列项;其他答案处理不可散列的。
  • @Prune 我明白了。我没有注意到解决不可散列问题的另一个答案,但这是一个相当糟糕的答案,因为当适当的解决方案应该在线性时间内完成时,它的时间复杂度会花费 O(n ^ 2)。跨度>

标签: python dictionary intersection hashset


【解决方案1】:

您可以创建一个“makeHashable”函数以应用于字典项目以进行比较,并使用它来构建一个集合,然后您可以检查列表理解:

dict1 = {'x':{1,2}, 'y':{2,3}, 'z':3}
dict2 = {'x':{1,3}, 'y':{3,2}, 'z':4}

def makeHashable(x):
    if isinstance(x,(list,tuple)):  return tuple(map(makeHashable,x))
    if isinstance(x,set):           return makeHashable(sorted(x))
    if isinstance(x,dict):          return tuple(map(makeHashable,x.items()))
    return x

dict1Set  = set(map(makeHashable,dict1.items()))
intersect = [ kv for kv in dict2.items() if makeHashable(kv) in dict1Set]

输出:

print(intersect) 

# [('y', {2, 3})]

【讨论】:

    【解决方案2】:

    不妨试试:

    #!/usr/local/cpython-3.8/bin/python3
    
    
    def intersection1(dict1, dict2):
        intersection = set(dict1.items()).intersection(dict2.items())
        return intersection
    
    
    def intersection2(dict1, dict2):
        result = {}
        for key1 in dict1:
            if key1 in dict2 and dict1[key1] == dict2[key1]:
                result[key1] = dict1[key1]
        return result
    
    
    def main():
        dict1 = {'x': 1, 'y': 2, 'z': 3}
        dict2 = {'x': 1, 'y': 2, 'z': 4}
    
        print(intersection2(dict1, dict2))
        print(intersection1(dict1, dict2))
        # >> {('x', 1), ('y', 2)}
    
        dict3 = {'x': [1, 2], 'y': [2, 3], 'z': [3, 4]}
        dict4 = {'x': [1, 2], 'y': [2, 3], 'z': [4, 5]}
    
        print(intersection2(dict3, dict4))
        print(intersection1(dict3, dict4))
    
    
    main()
    

    你当然不能把一个不可散列的类型放在一个集合中,所以我用 intersection2() 做了次好的事情

    【讨论】:

      【解决方案3】:

      您可以在执行集合交集之前序列化 dict 值,并反序列化结果集中的值。以下示例使用pickle 进行序列化:

      import pickle
      
      {k: pickle.loads(v) for k, v in set.intersection(
          *({(k, pickle.dumps(v)) for k, v in i} for i in map(dict.items, (dict1, dict2))))}
      

      所以给定:

      dict1 = {'x': {1, 2}, 'y': {2, 3}, 'z': 3}
      dict2 = {'x': {2, 1}, 'y': {2, 4}, 'z': 4}
      

      表达式将返回:

      {'x': {1, 2}}
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-07-05
        • 2017-07-11
        • 1970-01-01
        • 1970-01-01
        • 2016-03-16
        • 2016-12-09
        • 2021-12-22
        • 2013-03-30
        相关资源
        最近更新 更多