Compare two lists of tuples

假如想象 提交于 2019-12-01 00:07:06

You can use a 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')}

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. You could similarly handle the case of keys missing from new, but I didn't go that far.

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....

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

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:

[('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).

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":

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:

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:

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.

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:

from collections import OrderedDict
n,o=OrderedDict(new),OrderedDict(old)
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!