2017-04-06 127 views
2
old = [('ver','1121'),('sign','89'),('address','A45'),('type','00')] 
new = [('ver','1121'),('sign','89'),('type','01')] 

我需要根据元组的第一个元素来比较old一个new列表,并显示任何元素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)] 

UPDATE

感谢@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]))) 
+3

“address”会发生什么情况? – MooingRawr

+0

请建议如果通过列表遍历列表解析不能实现的任何其他方式。 – Ron

+0

由于它不在两个列表中,因此@MooingRawr –

回答

0

,你可以这样做:

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') 

但可以肯定的是有更多的 “Python化” 的方式....

0

下面是一个列表,列出所有的比较结果。根据您的新旧名单有多大,一套理解会工作多一点快,但速度会通过我下面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') 

现在排序comps基于在proper_order自定义语法:

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的顺序相同,但是对于更大的情况,两种方法之间的顺序差异将变得明显。

+0

“你的订单很重要吗?”是什么意思?你的意思是在“改变”之前你需要“相同”? – blacksite

+0

@not_a_robot,如果我在这两个列表中有重复的键,它是否工作? 说,旧的和新的列表还有一个元组('ver','blah') – Ron

+0

请参阅更新的方法。 – blacksite

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')} 
+0

'('type','00')'不再存在,但新添加了'('type','01')'。 –

+1

这是OP可以用来找出不匹配的工具:) –

0

这个怎么样:

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) 
1

有时列表理解不是的答案。这可能是其中的一次。此外,您不处理在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)) 
+0

我们可以使用'enumerate()'遍历这两个列表来照顾重复键吗? – Ron

+0

'枚举'只是简单地将数字分配给序列中的项目,所以我不确定它会如何帮助。但是,如果名单变得很大,那么可能会有一些可能。首先想到的是为每个列表构建一个字典,其键是元组的第一个元素,其值是该元组在列表中的位置。这将使得更快地确定正确的列表元素而不会迭代它(这是一个O(n/2)操作。 – holdenweb