2017-04-06 157 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