简体   繁体   English

比较两个元组列表

[英]Compare two lists of tuples

old = [('ver','1121'),('sign','89'),('address','A45'),('type','00')]
new = [('ver','1121'),('sign','89'),('type','01')]

I need to compare the new list against old one based on first element of the tuples, and show the difference between whatever elements new list has, so that the output should look like:我需要根据元组的第一个元素将new列表与old列表进行比较,并显示new列表具有的任何元素之间的差异,以便输出应如下所示:

Match     : ver   =   1121
Match     : sign  =   89
Mismatch  : type  =   01 (old : 00)

I could get all the matching tuples with below list comprehension but could not think beyond it.我可以通过以下列表理解获得所有匹配的元组,但无法超越它。

my_list = [(a,b) for (a,b) in new for (c,d) in old  if ((a==c) and (b==d))]
print( my_list)

Please suggest me a way to do it.请建议我一种方法。

EDIT编辑

I am sorry for not being clear on my question , I did not mention one more thing, the keys in the list can be repetitive, meaning the list can be like:很抱歉我的问题没有说清楚,我没有再提到一件事,列表中的键可以是重复的,这意味着列表可以是这样的:

old = [('ver','1121'),('sign','89'),('address','A45'),('type','00'),('ver','sorry')]

new = [('ver','1121'),('sign','89'),('type','01'),('ver','sorry)]

UPDATE更新

Thanks to @holdenweb, I've made some changes to his code and this seems to be providing the expected output, please suggest if there are any flaws.感谢@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])))

A set is a great tool for finding such mismatches: 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')}

What about this:那这个呢:

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

Output:输出:

Mismatch  :type     01       00
Match     :ver      1121     
Match     :sign     89      

If you need the order, try to use OrderedDict :如果您需要订单,请尝试使用OrderedDict

from collections import OrderedDict
n,o=OrderedDict(new),OrderedDict(old)

Sometimes a list comprehension isn't the answer.有时列表理解不是答案。 This may be one of those times.这可能是其中之一。 Also, you don't handle the case where a key is present in old but not in new - I include that case here, though you can chop out that code if it isn't relevant.此外,您不处理old密钥存在但new密钥不存在的情况 - 我在这里包括这种情况,但如果它不相关,您可以删除该代码。 You could similarly handle the case of keys missing from new , but I didn't go that far.您可以类似地处理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))

you can do something like :您可以执行以下操作:

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

that will give you :这会给你:

Match :  ('ver', '1121')
Match :  ('sign', '89')
Mismatch :  ('address', 'A45')
Mismatch :  ('type', '00')

But for sure there is a more "pythonic" way....但肯定有一种更“pythonic”的方式......

Here's a one-liner to get a list of all comparisons.这是一个用于获取所有比较列表的单行代码。 Depending on how big your old and new lists are, a set comprehension would work a bit more quickly, but that speed would be nullified by my sorted + itertools.groupby approach below (as sorted returns a list ):根据您的旧列表和新列表的大小,集合推导会更快地工作,但是我的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 is now: comps现在是:

[('ver', 'same', '1121'),
 ('sign', 'same', '89'),
 ('type', 'changed', '00', '01')]

Print it out:打印出来:

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

Edit: The following isn't exactly what OP wants, but I'll leave it anyway for those interested in seeing what stayed the same first, and what changed second (actually, you could define a custom grammar to sort by if you wanted to see the elements that changed first, but that's up to you).编辑:以下并不完全是 OP 想要的,但无论如何我都会把它留给那些有兴趣先看看什么保持不变,然后看看什么改变的人(实际上,如果你想的话,你可以定义一个自定义语法来排序查看首先更改的元素,但这取决于您)。

Prepare for using itertools.groupby , and taking into account OP's request for the printing order shown above, we can use a collections.OrderedDict object to create effectively an "ordered set" of "keys":准备使用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')

Now sort comps based on the custom grammar in proper_order :现在根据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')]

Use itertools.groupby to print:使用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

It just so happens that the order of this output is the same as what OP requested above, but for larger cases, the difference in order between the two approaches will become evident.碰巧这个输出的顺序与上面 OP 要求的顺序相同,但对于更大的情况,两种方法之间的顺序差异将变得明显。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM