2015-02-10 53 views
1

我有兩個列表如下所示。我知道我可以使用set(list1)--set(list2)或反之亦然打印與其他對應的列表不同的列表。但是,我不希望將完整列表打印出來,我只是希望修改列表中的那部分內容。使用Python的列表列表的差異

例如,列表1:

[['Code', 'sID', 'dID', 'cID', 'ssID'], ['ABCD-00', 'ABCD-00-UNK', '358', '1234', '9999'], ['ABCD-01', 'ABCD-00-UNK', 160, '993', '587']] 

列表2:

[['Code', 'sID', 'dID', 'cID', 'ssID', 'AddedColumn'], ['ABCD-00', 'ABCD-00-UNK', '358', '1234', '9999', 'AddedValue1'], ['ABCD-01', 'ABCD-00-UNK', 160, '993', 'ChangedValue', 'AddedValue2']] 

如果我不差集,它打印出整個列表。當'Code','sID'相同時,我希望輸出只顯示不同/添加/帶走的列。

每個列表的第一個列表是標題。所以我想比較'Code','sID'列中的值匹配時的列表。

所需的輸出:

​​3210

這樣的事情或任何簡單的是罰款也。

我已經試過代碼:

from difflib import SequenceMatcher 

matcher = SequenceMatcher() 
for a, b in zip(list1, list2): 
    matcher.set_seqs(a, b) 
    for tag, i1, i2, j1, j2 in matcher.get_opcodes(): 
     if tag == 'equal': continue 
     print('{:>7s} {} {}'.format(tag, a[i1:i2], b[j1:j2])) 

它運作良好,在比較對應列表,即子列表1中,在列表2子列表1列表1。但是我希望它能夠在整個列表中進行比較,因爲如果缺少特定的子列表,它會顯示所有內容都不相同。通過子列表我的意思是,例如列表1中的['Code', 'sID', 'dID', 'cID', 'ssID']是子列表1。

+0

你真的不能做「set(...) - set(...)」的事情:列表是可變對象,不能被設置成員 – jsbueno 2015-02-10 18:20:06

+0

你堅持使用列表和特定格式嗎?這看起來不太好。 – user3467349 2015-02-10 18:20:22

+0

@jsbueno我把它們改成了集合,我沒有在這個問題中加入。 – abn 2015-02-10 18:20:57

回答

0

這是我的基本解釋。 OP對於changed列表的內容並不十分清楚 - 所以他們應該更具體地更新他們的要求。作爲jsbueno暗示的字典可能會更好 - 這真的取決於列表是如果這是它進來格式便宜

added = [] 
deleted = [] 
changed = [] 
for sub_l1, sub_l2 in zip(l1, l2): 
    for i in range(min(len(sub_l1), len(sub_l2))): 
     if sub_l1[i] != sub_l2[i]: 
      changed.append(sub_l2[i]) 
    if len(sub_l2) > len(sub_l1): 
     added.append(sub_l2[len(sub_l1):len(sub_l2)]) 
    elif len(sub_l1) > len(sub_l2): 
     deleted.append(sub_l1[len(sub_l2):len(sub_l1)]) 

輸出樣本:

In [66]: added 
Out[66]: [['AddedColumn'], ['AddedValue1'], ['AddedValue2']] 
In [67]: deleted 
Out[67]: [] 
In [68]: changed 
Out[68]: ['ChangedValue'] 

注意changed是不會告訴你哪個。值發生了變化,通常您可能需要一個帶有CSV子列表和列號的元組。

+0

如果想法是對兩個列表中的所有元素進行亂序比較,即O(m×n),O(m×1) – jsbueno 2015-02-11 11:12:31

+0

這不是一個輸出(至少就我對OP的問題的回答和理解而言)。如果所有數據已經​​組織在一個表中,則哈希查找不會提供很多優勢。 (解析一次得到所有修改值的行,列元組,然後查找便宜)。附:我同意一般散列對象更容易處理,就像我在我的帖子中所說的那樣,它取決於應用程序。 – user3467349 2015-02-11 12:04:33

1

所以 - 正如人們在評論中所說的那樣,你真正應該做的就是將你稱爲「子列表」的每組數據讀入適當的對象中,然後他們比較這些對象的屬性。例如,要堅持本機類型,如果「代碼」和「sID」組成了你的密鑰,那麼每一行都可能是由你的代碼和sid值組成的字典。

但htis問題似乎調用自定義類 - -

鑑於上述列表中的一個 - 你可以幾乎沿東西開始:

class MyThing(object): 
    def __init__(self, *args): 
     for attrname, arg in zip(['Code', 'sID', 'dID', 'cID', 'ssID'], args): 
      setattr(self, attrname, arg) 

    def __hash__(self): 
     # This is not needed for the OrderedDict bwellow, but allows you 
     # to use sets with the objects if you want 
     return hash(self.Code + self.sID) 

from collections import OrderedDict 
myobjs = OrderedDict() 
for line in list1[1:]: 
    obj = MyThing(line) 
    id = obj.Code + obj.sId 
    if id in myobjs: 
     # do your comparisson -logging -printing stuff here 
    else: 
     myobjs[id] = obj 

它實際上可以不進行類和對象創建部分 - 只需將「行」存儲在字典中 - 但該類使您能夠以更簡潔的方式完成很多事情。複雜的__init__只是一個簡寫,不會複製大量的self.sId = sId行。

+0

感謝您的回覆。但是,棘手的部分是我有多個文件,標題可能會改變。 – abn 2015-02-10 18:33:25

+0

這對上面的代碼來說應該不難 - 只要在硬編碼頭文件的那一行,並在文件的第一行添加引用即可。如果他們不總是「代碼」和「標準」,你將不得不適應你的關鍵領域。 – jsbueno 2015-02-11 11:10:15