关于python:获取包含字典的2个列表之间的区别

Getting the difference between 2 lists that contain dictionaries

本问题已经有最佳答案,请猛点这里访问。
1
2
list1 = [{'key1': 'item1'}, {'key2': 'item2'}]
list2 = [{'key1': 'item1'}, {'key2': 'item2'}, {'key3': 'item3'}]

这两个清单有什么区别吗?

基本上,我需要一种可伸缩的方法来获得包含字典的两个列表之间的差异。所以我想比较一下这些列表,得到一个{'key3': 'item3'}的返回。


您可以使用列表理解:

1
2
3
4
list1 = [{'key1': 'item1'}, {'key2': 'item2'}]
list2 = [{'key1': 'item1'}, {'key2': 'item2'}, {'key3': 'item3'}]

print([x for x in list2 if x not in list1])

这将给EDOCX1[0]


您可以使用set()进行如下理解:

1
2
3
4
5
6
7
8
9
10
11
def get_diff(elm1, elm2):
    a = set((m, n) for k in elm1 for m, n in k.items())
    b = set((m, n) for k in elm2 for m, n in k.items())
    if len(b) > len(a):
        return dict(b - a)
    return dict(a - b)


list1 = [{'key1': 'item1'}, {'key2': 'item2'}]
list2 = [{'key1': 'item1'}, {'key2': 'item2'}, {'key3': 'item3'}]
get_diff(list1, list2)

输出:

1
{'key3': 'item3'}


1
2
in_list1_not_in_list2 = [i for i in list1 if i not in list2]
in_list2_not_in_list1 = [i for i in list2 if i not in list1]

您也可以尝试使用set.symmetric_difference()来获得两种方法之间的差异:

1
2
3
4
5
6
7
8
9
10
11
list1 = [{'key1': 'item1'}, {'key2': 'item2'}]
list2 = [{'key1': 'item1'}, {'key2': 'item2'}, {'key3': 'item3'}]

set1 = set(tuple(x.items())[0] for x in list1)
set2 = set(tuple(x.items())[0] for x in list2)

print([dict(list(set1.symmetric_difference(set2)))])
# [{'key3': 'item3'}]

print([dict(list(set2.symmetric_difference(set1)))])
# [{'key3': 'item3'}]

另一种方法是使用itertools.filterfalse()

1
2
3
4
5
6
7
from itertools import filterfalse

diff1 = list(filterfalse(lambda d: d in list2, list1))
diff2 = list(filterfalse(lambda d: d in list1, list2))

print(diff1 + diff2)
# [{'key3': 'item3'}]

您可以通知字典如何散列自身,然后可以使用集合

1
2
3
4
5
6
import json

class HashableDict(dict):  
    def __hash__(self):
        # convert the dictionary to something hashable - in this case a str
        return hash(json.dumps(self))

然后你可以做

1
2
3
hashable_list1 = map(HashableDict, list1)
hashable_list2 = map(HashableDict, list2)
set(hashable_list2).difference(hashable_list1)

difference为您提供列表2中不在列表1中的元素。

如果你想要所有的区别,那么所有不在这两个列表中的项目都需要:

1
set(hashable_list2).symmetric_difference(hashable_list1)

注意:这不适用于所有字典(例如,包含json.dumps无法使用的对象的字典),除非您也使用自定义JSONEncoder显式地处理这些字典。


因为字典不可散列,所以散列不是一种简单的方法,但是因为每个字典都有一个键和一个VAL,所以我们可以构建自己的键!所以你可以这样做:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
list1_set = set()

for dictionary in list1:
    key = dictionary.keys()[0]
    vals = dictionary.values()[0]
    custom_key = '{}|{}'.format(key,vals)
    list1_set.add(custom_key)

differences = []
for dictionary in list2:
    key = dictionary.keys()[0]
    vals = dictionary.values()[0]
    custom_key = '{}|{}'.format(key,vals)

    if custom_key not in list1_set:
        differences.append(dictionary)

print differences

输出:

1
[{'key3': 'item3'}]

不是因为这个解决方案具有持续的查找能力,所以它比简单地遍历第一个列表更具可伸缩性。