Пересечение dict_values ​​и хэшируемые типы - PullRequest
0 голосов
/ 20 марта 2020

Я хотел бы проверить пересечение двух словарей. Если я сделаю это, я получу именно то, что ожидал:

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'

Конечно, я получаю ту же ошибку для кортежей и списков, так как они также не могут быть хэшируемыми.

Существует ли обходной путь или существующий класс, который я могу использовать для проверки пересечения неисчерпаемых значений словаря?

Ответы [ 3 ]

0 голосов
/ 20 марта 2020

Вы можете сериализовать значения 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}}
0 голосов
/ 20 марта 2020

Вы можете создать функцию «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]

output:

print(intersect) 

# [('y', {2, 3})]
0 голосов
/ 20 марта 2020

Возможно, попробуйте:

#!/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 ()

...