[英]Compare two lists of tuples
old = [('ver','1121'),('sign','89'),('address','A45'),('type','00')]
new = [('ver','1121'),('sign','89'),('type','01')]
我需要根据元组的第一个元素将new
列表与old
列表进行比较,并显示new
列表具有的任何元素之间的差异,以便输出应如下所示:
Match : ver = 1121
Match : sign = 89
Mismatch : type = 01 (old : 00)
我可以通过以下列表理解获得所有匹配的元组,但无法超越它。
my_list = [(a,b) for (a,b) in new for (c,d) in old if ((a==c) and (b==d))]
print( my_list)
请建议我一种方法。
编辑
很抱歉我的问题没有说清楚,我没有再提到一件事,列表中的键可以是重复的,这意味着列表可以是这样的:
old = [('ver','1121'),('sign','89'),('address','A45'),('type','00'),('ver','sorry')]
new = [('ver','1121'),('sign','89'),('type','01'),('ver','sorry)]
更新
感谢@holdenweb,我对他的代码进行了一些更改,这似乎提供了预期的输出,如果有任何缺陷,请提出建议。
old = [('ver','1121'),('sign','89'),('address','A45'),('type','00'),('ver','works?')]
new = [('ver','1121'),('sign','89'),('type','01'),('ver','This')]
formatter = "{:12}: {:8} = {}".format
newfmter = "{} (old : {})".format
kv_old = []
for i,(kn, vn) in enumerate(new):
vo = [(j,(ko,vo)) for j,(ko, vo) in enumerate(old) if (ko==kn) ]
for idx,(key,val) in vo:
if idx >=i:
kv_old = [key,val]
break;
if kv_old[1]==vn:
print(formatter("Match", kv_old[0], kv_old[1]))
else:
print(formatter("Mismatch", kn, newfmter(vn, kv_old[1])))
set
是查找此类不匹配的绝佳工具:
>>> old = [('ver','1121'),('sign','89'),('address','A45'),('type','00')]
>>> new = [('ver','1121'),('sign','89'),('type','01')]
>>> print('no longer there:', set(old) - set(new))
no longer there: {('type', '00'), ('address', 'A45')}
>>> print('newly added:', set(new) - set(old))
newly added: {('type', '01')}
>>> print('still there:', set(old) & set(new))
still there: {('sign', '89'), ('ver', '1121')}
那这个呢:
n,o=dict(new),dict(old)
for i in n:
print "{0:10}:{2:8} {3:8} {1}".format(*(("Match","") if o.get(i)==n[i] else ("Mismatch",o.get(i,i)))+ (i,n[i]))
输出:
Mismatch :type 01 00
Match :ver 1121
Match :sign 89
如果您需要订单,请尝试使用OrderedDict
:
from collections import OrderedDict
n,o=OrderedDict(new),OrderedDict(old)
有时列表理解不是答案。 这可能是其中之一。 此外,您不处理old
密钥存在但new
密钥不存在的情况 - 我在这里包括这种情况,但如果它不相关,您可以删除该代码。 您可以类似地处理new
缺少键的情况,但我没有走那么远。
old = [('ver','1121'),('sign','89'),('address','A45'),('type','00')]
new = [('ver','1121'),('sign','89'),('type','01'),("sneaky", 'not there before')]
formatter = "{:12}: {:8} = {}".format
newfmter = "{} (old : {})".format
for (kn, vn) in new:
if any(ko==kn for (ko, vo) in old):
ko, vo = [(ko, vo) for (ko, vo) in old if ko==kn][0]
if vo==vn:
print(formatter("Match", ko, vo))
else:
print(formatter("Mismatch", kn, newfmter(vn, vo)))
else:
print(formatter("New", kn, vn))
您可以执行以下操作:
old = [('ver','1121'),('sign','89'),('address','A45'),('type','00')]
new = [('ver','1121'),('sign','89'),('type','01')]
my_list = [(a,b) for (a,b) in new for (c,d) in old if ((a==c) and (b==d))]
for i in old:
if i in my_list:
print "Match : ", i
else:
print "Mismatch : ", i
这会给你:
Match : ('ver', '1121')
Match : ('sign', '89')
Mismatch : ('address', 'A45')
Mismatch : ('type', '00')
但肯定有一种更“pythonic”的方式......
这是一个用于获取所有比较列表的单行代码。 根据您的旧列表和新列表的大小,集合推导会更快地工作,但是我的sorted
+ itertools.groupby
方法会抵消这种速度(因为sorted
返回一个list
):
comps = [(key, 'changed', old_val, new_val)
if old_val != new_val else (key, 'same', old_val)
for key, old_val in old for oth_key, new_val in new
if key == oth_key]
comps
现在是:
[('ver', 'same', '1121'),
('sign', 'same', '89'),
('type', 'changed', '00', '01')]
打印出来:
for t in comps:
if len(t) == 3:
print('%s: %s, value: %s' % (t[1], t[0], t[2]))
else:
print('%s: %s, value: %s' % (t[1], t[0], ', '.join(t[2:])))
same: ver, value: 1121
same: sign, value: 89
changed: type, value: 00, 01
编辑:以下并不完全是 OP 想要的,但无论如何我都会把它留给那些有兴趣先看看什么保持不变,然后看看什么改变的人(实际上,如果你想的话,你可以定义一个自定义语法来排序查看首先更改的元素,但这取决于您)。
准备使用itertools.groupby
,并考虑到 OP 对上面显示的打印顺序的请求,我们可以使用collections.OrderedDict
对象来有效地创建“键”的“有序集”:
import collections
proper_order = tuple(collections.OrderedDict.fromkeys([x[0] for x in new]).keys())
proper_order
Out[43]: ('ver', 'sign', 'type')
现在根据proper_order
的自定义语法对comps
进行排序:
comps_sorted = sorted(comps, key=lambda x: proper_order.index(x[0]))
comps_sorted
Out[45]:
[('ver', 'same', '1121'),
('sign', 'same', '89'),
('type', 'changed', '00', '01')]
使用itertools.groupby
打印:
for key, group in itertools.groupby(comps_sorted, key=lambda x: x[1]):
for g in group:
print('%s: %s' % (key, ', '.join(x for x in g if x not in ('same', 'changed'))))
same: ver, 1121
same: sign, 89
changed: type, 00, 01
碰巧这个输出的顺序与上面 OP 要求的顺序相同,但对于更大的情况,两种方法之间的顺序差异将变得明显。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.