词典列表的差异
Difference of list of dictionaries
我搜索了很多,但没有找到与该问题类似的问题。
我有两个字典列表,格式如下:
data1 = [
{'id': 4, 'date_time': datetime.datetime(2020, 4, 3, 12, 34, 40)},
{'id': 4, 'date_time': datetime.datetime(2020, 4, 3, 12, 34, 40)},
{'id': 6, 'date_time': datetime.datetime(2020, 4, 3, 12, 34, 40)},
{'id': 7, 'date_time': datetime.datetime(2020, 4, 3, 16, 14, 21)},
]
data2 = [
{'id': 4, 'date_time': datetime.datetime(2020, 4, 3, 12, 34, 40)},
{'id': 6, 'date_time': datetime.datetime(2020, 4, 3, 12, 34, 40)},
]
期望输出:
final_data = [
{'id': 4, 'date_time': datetime.datetime(2020, 4, 3, 12, 34, 40)},
{'id': 7, 'date_time': datetime.datetime(2020, 4, 3, 16, 14, 21)},
]
我只想要 data1
而不是 data2
中的词典。
直到现在,当我在两个 for 循环中找到一个匹配项时,我将字典从列表中弹出,但这对我来说似乎不是一个好方法。我怎样才能达到预期的输出?
它不需要时间效率,因为每个列表中最多会有几十个词典
当前实施:
counter_i = 0
for i in range(len(data1)):
counter_j = 0
for j in range(len(data2)):
if data1[i-counter_i]['id'] == data2[j-counter_j]['id'] and data1[i-counter_i]['date_time'] == data2[j-counter_j]['date_time']
data1.pop(i-counter_i)
data2.pop(j-counter_j)
counter_i += 1
counter_j += 1
break
如果性能不是问题,为什么不呢:
for d in data2:
try:
data1.remove(d)
except ValueError:
pass
list.remove
检查对象是否相等,而不是标识,因此适用于具有相同键和值的字典。此外,list.remove
一次只删除一个。
你可以选择任何一种方式:
方法一:
#using filter and lambda function
final_data = filter(lambda i: i not in data2, data1)
final_data = list(final_data)
方法二:
# using list comprehension to perform task
final_data = [i for i in data1 if i not in data2]
schwobaseggl 的答案可能是最干净的解决方案(如果您需要保持 data1 完好无损,只需在删除前制作一个副本)。
但是如果你想使用集合差异...那么字典是不可哈希的,因为它们的基础数据可能会改变并导致问题(列表或集合也不可哈希的原因相同)。
但是,您可以获取 frozenset 中的所有字典对来表示字典(假设字典值是可哈希的 -schwobaseggl)。 frozensets 是可散列的,所以你可以将它们添加到一个集合中,做一个正常的集合差异。并在最后重建字典 :D.
我实际上并不推荐这样做,但我们开始吧:
final_data = [
dict(s)
for s in set(
frozenset(d.items()) for d in data1
).difference(
frozenset(d.items()) for d in data2
)
]
我搜索了很多,但没有找到与该问题类似的问题。
我有两个字典列表,格式如下:
data1 = [
{'id': 4, 'date_time': datetime.datetime(2020, 4, 3, 12, 34, 40)},
{'id': 4, 'date_time': datetime.datetime(2020, 4, 3, 12, 34, 40)},
{'id': 6, 'date_time': datetime.datetime(2020, 4, 3, 12, 34, 40)},
{'id': 7, 'date_time': datetime.datetime(2020, 4, 3, 16, 14, 21)},
]
data2 = [
{'id': 4, 'date_time': datetime.datetime(2020, 4, 3, 12, 34, 40)},
{'id': 6, 'date_time': datetime.datetime(2020, 4, 3, 12, 34, 40)},
]
期望输出:
final_data = [
{'id': 4, 'date_time': datetime.datetime(2020, 4, 3, 12, 34, 40)},
{'id': 7, 'date_time': datetime.datetime(2020, 4, 3, 16, 14, 21)},
]
我只想要 data1
而不是 data2
中的词典。
直到现在,当我在两个 for 循环中找到一个匹配项时,我将字典从列表中弹出,但这对我来说似乎不是一个好方法。我怎样才能达到预期的输出?
它不需要时间效率,因为每个列表中最多会有几十个词典
当前实施:
counter_i = 0
for i in range(len(data1)):
counter_j = 0
for j in range(len(data2)):
if data1[i-counter_i]['id'] == data2[j-counter_j]['id'] and data1[i-counter_i]['date_time'] == data2[j-counter_j]['date_time']
data1.pop(i-counter_i)
data2.pop(j-counter_j)
counter_i += 1
counter_j += 1
break
如果性能不是问题,为什么不呢:
for d in data2:
try:
data1.remove(d)
except ValueError:
pass
list.remove
检查对象是否相等,而不是标识,因此适用于具有相同键和值的字典。此外,list.remove
一次只删除一个。
你可以选择任何一种方式:
方法一:
#using filter and lambda function
final_data = filter(lambda i: i not in data2, data1)
final_data = list(final_data)
方法二:
# using list comprehension to perform task
final_data = [i for i in data1 if i not in data2]
schwobaseggl 的答案可能是最干净的解决方案(如果您需要保持 data1 完好无损,只需在删除前制作一个副本)。
但是如果你想使用集合差异...那么字典是不可哈希的,因为它们的基础数据可能会改变并导致问题(列表或集合也不可哈希的原因相同)。
但是,您可以获取 frozenset 中的所有字典对来表示字典(假设字典值是可哈希的 -schwobaseggl)。 frozensets 是可散列的,所以你可以将它们添加到一个集合中,做一个正常的集合差异。并在最后重建字典 :D.
我实际上并不推荐这样做,但我们开始吧:
final_data = [
dict(s)
for s in set(
frozenset(d.items()) for d in data1
).difference(
frozenset(d.items()) for d in data2
)
]