使用Python的列表列表的差异

时间:2015-02-10 18:08:14

标签: python list set compare

我有两个列表,如下所示。我知道我可以使用set(list1)-set(list2)或反之亦然来打印与其他对应列表不同的列表。但是,我不希望打印出完整的列表,我只是希望列表中的那部分被修改。

例如,list1:

[['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']]

如果我设置了差异,它会打印出整个列表。我希望输出只显示不同/添加/删除的列,而代码',' sID'是相同的。

每个列表列表的第一个列表是标题。所以我想比较来自' Code',' sID'列匹配。

期望的输出:

Added - ['AddedColumn', 'AddedValue1', 'AddedValue2']
Deleted - []
Changed - ['Code', 'ABCD-01', 'ssID', 'ChangeValue']

类似这样或更简单的东西也可以。

我试过的代码:

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

它可以很好地比较相应的列表,即list1中的sub-list1和list2中的sub-list1。但是我希望它在整个列表中进行比较,因为如果缺少某个特定的子列表,它会打印出一切都不同。通过子列表我的意思是,例如list1中的['Code', 'sID', 'dID', 'cID', 'ssID']是子列表1。

2 个答案:

答案 0 :(得分: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行的简写。

答案 1 :(得分:0)

这是我的基本解释。 OP对于他们对{​​{1}}列表的要求并不十分清楚 - 所以他们应该更具体地更新他们的要求。正如jsbueno所暗示的那样,dict可能会更好 - 这实际上取决于,如果这是它的格式,那么列表会更便宜。

changed

示例输出:

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'] 并未告诉您哪个值发生了更改,通常您可能需要一个包含CSV子列表和列号的元组。