Ответ 1
Вы можете использовать понимание списка:
list1 = [{'key1': 'item1'}, {'key2': 'item2'}]
list2 = [{'key1': 'item1'}, {'key2': 'item2'}, {'key3': 'item3'}]
print([x for x in list2 if x not in list1])
Что даст [{'key3': 'item3'}]
list1 = [{'key1': 'item1'}, {'key2': 'item2'}]
list2 = [{'key1': 'item1'}, {'key2': 'item2'}, {'key3': 'item3'}]
Есть ли способ получить разницу между этими двумя списками?
По сути, мне нужен масштабируемый способ получить различия между двумя списками, которые содержат словари. Поэтому я пытаюсь сравнить эти списки и просто получить возвращение {'key3': 'item3'}
Вы можете использовать понимание списка:
list1 = [{'key1': 'item1'}, {'key2': 'item2'}]
list2 = [{'key1': 'item1'}, {'key2': 'item2'}, {'key3': 'item3'}]
print([x for x in list2 if x not in list1])
Что даст [{'key3': 'item3'}]
Вы можете использовать set()
с пониманием, как этот пример:
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)
Выход:
{'key3': 'item3'}
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]
Поскольку словари не могут быть хешируемыми, хэшировать не так просто, но так как у нас есть один ключ и одно значение на каждый словарь, мы можем создать наш собственный ключ! Так что вы можете сделать что-то вроде этого:
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
выход:
[{'key3': 'item3'}]
Не это решение гораздо более масштабируемо, чем просто повторение первого списка из-за возможности постоянного поиска.
Вы можете сообщить словарю, как хэшировать себя, а затем вы можете использовать наборы
import json
class HashableDict(dict):
def __hash__(self):
# convert the dictionary to something hashable - in this case a str
return hash(json.dumps(self))
тогда вы можете сделать
hashable_list1 = map(HashableDict, list1)
hashable_list2 = map(HashableDict, list2)
set(hashable_list2).difference(hashable_list1)
difference
дает вам элементы в lists2, которых нет в list1.
Если вам нужна вся разница, поэтому все элементы, которых нет в обоих списках, выполните:
set(hashable_list2).symmetric_difference(hashable_list1)
Обратите внимание, что это не будет работать для всех словарей (например, словарей, содержащих объекты, с json.dumps
не может работать), если вы не обрабатываете их явно с помощью специального JSONEncoder
Вы также можете попробовать использовать set.symmetric_difference()
чтобы получить разницу между наборами в обоих направлениях:
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()
:
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'}]