我想得到两个具有以下结构的列表的区别:
first_dict = [{"a": "abcd","b":"defg", "c":["fng","xvg"]}, {"a": "stg","b":"klsm", "c":["xzy"]}]
second_dict = [{"a": "abcd","b":"defg", "c":["fng","xvg"]}]
我试图冻结集合,如下所示:
i_set = { frozenset(row.items()) for row in first_dict }
a_set = { frozenset(row.items()) for row in second_dict }
result = [dict(i) for i in i_set - a_set]
预期结果:
v = {"a": "stg","b":"klsm", "c":["xzy"]}
由于"c":[]
是一个列表,因此出现以下错误:
TypeError: unhashable type: 'list'
答案 0 :(得分:1)
由于您使用过set
和frozenset
,所以我假设您关心效率,并且不希望使用O(n**2)
算法。
在这种情况下,您不仅需要将字典转换为Frozensets,还可以将列表转换为可哈希类。您可以使用tuple
s。
假设您输入以下内容:
first_dict = [{"a": "abcd","b":"defg", "c":["fng","xvg"]}, {"a": "stg","b":"klsm", "c":["xzy"]}]
second_dict = [{"a": "abcd","b":"defg", "c":["fng","xvg"]}]
您可以使用:
def convert(dictionary):
return frozenset((key, tuple(value) if isinstance(value, list) else value) for key, value in dictionary.items())
def convert_back(frozset):
return dict((key, list(value) if isinstance(value, tuple) else value) for key, value in frozset)
i_set = { convert(row) for row in first_dict }
a_set = { convert(row) for row in second_dict }
result = [convert_back(i) for i in i_set - a_set]
那么结果将是:
[{'a': 'stg', 'c': ['xzy'], 'b': 'klsm'}]
但是,这不会区分原来为元组的元组和原来为元组的元组。
您可以通过将字典包装在您自己的可哈希类中来解决此问题(如果您确定字典及其内容在操作期间不会发生突变)。这样做的好处是,您以后无需将它们转换回去,只需简单地“解包”值即可。
class HashableDictionaryWithListValues:
def __init__(self, dictionary):
converted = frozenset((key, tuple(value) if isinstance(value, list) else value) for key, value in dictionary.items())
self._hash = hash(converted)
self._converted = converted
self.dictionary = dictionary
def __hash__(self):
return self._hash
def __eq__(self, other):
return self._converted == other._converted
i_set = { HashableDictionaryWithListValues(row) for row in first_dict }
a_set = { HashableDictionaryWithListValues(row) for row in second_dict }
result = [i.dictionary for i in i_set - a_set]
结果将是:
[{'a': 'stg', 'b': 'klsm', 'c': ['xzy']}]
尽管您也可以避免整个转换/包装,并采取O(n**2)
的方法:
def difference(first, second):
for item in first:
if item not in second:
yield item
list(difference(first_dict, second_dict))
还能给出预期的结果:
[{'a': 'stg', 'b': 'klsm', 'c': ['xzy']}]
答案 1 :(得分:0)
为什么frozenset
?,只需使用:
>>> first_dict = [{"a": "abcd","b":"defg", "c":["fng","xvg"]}, {"a": "stg","b":"klsm", "c":["xzy"]}]
>>> second_dict = [{"a": "abcd","b":"defg", "c":["fng","xvg"]}]
>>> [i for i in first_dict if i not in second_dict]
[{'a': 'stg', 'b': 'klsm', 'c': ['xzy']}]
>>>
或者,如果您想要一个单数,请更改:
>>> [i for i in first_dict if i not in second_dict]
收件人:
>>> [i for i in first_dict if i not in second_dict][0]
哪个输出:
{'a': 'stg', 'b': 'klsm', 'c': ['xzy']}