2015-02-10 23 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