簡體   English   中英

比較兩個元組列表

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM