比较字典列表和python中的嵌套列表

时间:2019-06-02 11:02:04

标签: python arrays list dictionary

我想得到两个具有以下结构的列表的区别:

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'

我看过类似的答案herehere,但是它们不能解决我的问题。

2 个答案:

答案 0 :(得分:1)

由于您使用过setfrozenset,所以我假设您关心效率,并且不希望使用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']}