查找Python中两个列表之间的差异
如何通过比较对象的一个属性来找出两个对象之间的差异 在本例中,如果两个对象的查找Python中两个列表之间的差异,python,python-2.7,Python,Python 2.7,如何通过比较对象的一个属性来找出两个对象之间的差异 在本例中,如果两个对象的phone属性相同,则称它们彼此相等 a1 = {'name':'Tom', 'phone':'1234'} a2 = {'name':'Dick', 'phone':'1111'} a3 = {'name':'Harry', 'phone':'3333'} a = [a1,a2,a3] b1 = {'name':'Jane', 'phone':'1234'} b2 = {'name':'Liz', 'phone':'
phone
属性相同,则称它们彼此相等
a1 = {'name':'Tom', 'phone':'1234'}
a2 = {'name':'Dick', 'phone':'1111'}
a3 = {'name':'Harry', 'phone':'3333'}
a = [a1,a2,a3]
b1 = {'name':'Jane', 'phone':'1234'}
b2 = {'name':'Liz', 'phone':'2222'}
b3 = {'name':'Mary', 'phone':'4444'}
b = [b1,b2,b3]
def check(x, y):
if(x['phone'] == y['phone']):
return True
else:
return False
预期结果应为:
result_A_minus_B = [a2, a3]
result_B_minus_A = [b2, b3]
我在下面的尝试抛出了一个错误TypeError:列表索引必须是整数,而不是str
[x for x in a if check(a,b)]
对于给定的数据结构,您必须重复遍历第二个字典列表中的项,这是相对低效的。您所关心的只是第二个字典列表中是否已经存在给定的电话号码。重复测试给定值是否存在的最有效的数据结构是
set
(或者dict
,如果您可能需要从电话号码索引回更多信息)。因此,我将按照以下方式进行:
a = [a1, a2, a3]
b = [b1, b2, b3]
a_phone_numbers_set = set(d['phone'] for d in a])
b_phone_numbers_set = set(d['phone'] for d in b])
result_A_minus_B = [d for d in a if d['phone'] not in b_phone_numbers_set]
result_B_minus_A = [d for d in b if d['phone'] not in a_phone_numbers_set]
或者,如果我想创建一个函数:
def unmatched_entries(list1, list2):
existing_entries = set(d['phone'] for d in list2)
return [d for d in list1 if d['phone'] not in existing_entries]
def minus(list1, list2):
return [x for x in list1 if x['phone'] not in set(y['phone'] for y in list2)]
或者,您可以使用任意密钥:
def unmatched_entries(list1, list2, matching_key):
existing_entries = set(d[matching_key] for d in list2 if matching_key in d)
return [d for d in list1 if matching_key in d and d[matching_key] not in existing_entries]
该版本总是跳过列表1中没有定义请求的键的条目-其他行为是可能的
为了匹配一条简短注释中提到的多个键,我将使用一组值元组:
a_match_elements = set((d['phone'], d['email']) for d in a])
result_B_minus_a = [d for d in b if (d['phone'], d['email']) not in a_match_elements]
同样,可以将其推广到处理一系列键。此函数:
def unmatched_entries(list1, list2):
existing_entries = set(d['phone'] for d in list2)
return [d for d in list1 if d['phone'] not in existing_entries]
def minus(list1, list2):
return [x for x in list1 if x['phone'] not in set(y['phone'] for y in list2)]
给出了以下结果:
>>> minus(a, b)
[{'name': 'Dick', 'phone': '1111'}, {'name': 'Harry', 'phone': '3333'}]
>>> minus(b, a)
[{'name': 'Liz', 'phone': '2222'}, {'name': 'Mary', 'phone': '4444'}]
如果可以更改数据类型,dict可能会更好。您可以使用电话号码作为检索姓名的键
a = {'1234':'Tom','1111':'Dick','3333':'Harry'}
b = {'1234':'Jane', '2222':'Liz','4444':'Mary'}
def minus(x, y):
{z:a[z] for z in set(x.keys()) - set(y.keys())}
# {'1111':'Dick','3333':'Harry'}
a_minus_b = minus(a, b)
# {'2222':'Liz','4444':'Mary'}
b_minus_a = minus(b, a)
这很简洁,但效率很低-是顺序len(列表1)*len(列表2)。对于示例短列表很好,但对于较大的数据集不是一个好的算法。从理解之外的
list2
中收集所有电话值没有坏处。对于按电话号码索引的dict来说,这很好,但这不是OP开始的数据结构。如果不在实现中,设置差异将比更快,但要使其起作用,您必须创建反向查找dict和该dict的集合-您进行过任何分析吗?我不是说这不是更快,只是想看到一些数字。我只是提供了一个替代方案,这就是为什么我开始说“如果你可以更改数据类型”。我不是说这是最好的解决方案,特别是如果他计划在“a”或“b”中有多个数字相同的人显然行不通。但是,如果这满足了他的需要,它肯定很容易使用和理解。示例数据结构肯定不太理想。这不是链接问题的重复。这个问题是关于计算一个列表中连续元素之间的差异,而这个问题是关于如果第二个列表中的其他任何地方出现了相应的元素,则从一个列表中排除元素。