查找并更新列表列表中的重复项

时间:2011-07-18 16:15:26

标签: python list duplicates

我正在寻找一种解决以下问题的Pythonic方法。我(我认为)是一个有效的解决方案,但它有复杂的流量控制,只是不“漂亮”。 (基本上是一个C ++解决方案)

我有一份清单清单。每个列表包含多个不同类型的项目(每个列表可能有10个项目)列表的整体顺序不相关,但任何单个列表中项目的顺序都很重要。 (即我无法改变它。)

我希望通过在单个列表的末尾添加一个额外字段来“标记”重复项。但是,在这种情况下,“重复”列表是在几个预选字段中具有相等值的列表,但不是所有字段(没有“真实”重复项)。

例如:如果这是来自5个项目列表的原始数据,则复制被定义为在第一个和第三个字段中具有相等的值:

['apple', 'window', 'pear', 2, 1.55, 'banana']
['apple', 'orange', 'kiwi', 3, 1.80, 'banana']
['apple', 'envelope', 'star_fruit', 2, 1.55, 'banana']
['apple', 'orange', 'pear', 2, 0.80, 'coffee_cup'] 
['apple', 'orange', 'pear', 2, 3.80, 'coffee_cup']

第一,第四和第五个列表将是重复的,因此所有列表应更新如下:

['apple', 'window', 'pear', 2, 1.55, 'banana', 1]
['apple', 'orange', 'kiwi', 3, 1.55, 'banana', 0]
['apple', 'envelope', 'star_fruit', 2, 1.55,'banana', 0]
['apple', 'orange', 'pear', 2, 3.80, 'coffee_cup', 2]  
['apple', 'orange', 'pear', 2, 3.80, 'coffee_cup', 3]

感谢您的帮助或指导。我认为这可能超出了学习Python的书。

3 个答案:

答案 0 :(得分:3)

from collections import defaultdict

lists = [['apple', 'window', 'pear', 2, 1.55, 'banana'],
['apple', 'orange', 'kiwi', 3, 1.80, 'banana'],
['apple', 'envelope', 'star_fruit', 2, 1.55, 'banana'],
['apple', 'orange', 'pear', 2, 0.80, 'coffee_cup'],
['apple', 'orange', 'pear', 2, 3.80, 'coffee_cup']]

dic = defaultdict(int)
fts = []
for lst in lists:
    first_third = lst[0], lst[2]
    dic[first_third] += 1
    if dic[first_third] == 2: fts.append(first_third)
    lst.append(dic[first_third])

for lst in lists:
    if (lst[0], lst[2]) not in fts:
        lst[-1] -= 1

print(lists)

编辑:谢谢utdemir。 first_third = lst[0], lst[2]是正确的,而不是first_third = lst[0] + lst[2]

Edit2:为了清晰起见,更改了变量名称。

Edit3:改变以反映原始海报真正想要的内容,以及他的更新列表。不再那么好了,所需要的改变刚刚加入。

答案 1 :(得分:1)

您最好的选择是先使用itemgetter()对列表进行排序,然后选择要匹配的字段key。这将导致所有匹配的关键字段一起显示,以便可以轻松地进行比较和标记。例如,匹配第一个和第三个字段的排序是:

lst.sort(key=itemgetter(0, 2))

每个项目与其前身的比较是直截了当的。

好的,这是完整的解决方案(使用itemgetter和groupby):

from operator import itemgetter
from itertools import groupby

def tagdups(input_seq, tag, key_indexes):
    keygetter = itemgetter(*key_indexes)
    sorted_list = sorted(input_seq, key=keygetter)
    for key, group in groupby(sorted_list, keygetter):
        group_list = list(group)
        if len(group_list) <= 1:
            continue
        for item in group_list:
            item.append(tag)
    return sorted_list

这是一个示例测试运行以显示用法:

>>> samp = [[1,2,3,4,5], [1,3,5,7,7],[1,4,3,5,8],[4,3,2,7,5],[1,6,3,7,4]]
>>> tagdups(samp, 'dup', (0,2))
[[1, 2, 3, 4, 5, 'dup'], [1, 4, 3, 5, 8, 'dup'], [1, 6, 3, 7, 4, 'dup'], [1, 3, 5, 7, 7], [4, 3, 2, 7, 5]]

答案 2 :(得分:0)

这是我的解决方案(评论代码):

import itertools

l = [
        ['apple', 'window', 'pear', 2, 1.55, 'banana'],
        ['apple', 'orange', 'kiwi', 3, 1.80, 'banana'],
        ['apple', 'envelope', 'star_fruit', 2, 1.55, 'banana'],
        ['apple', 'orange', 'pear', 2, 0.80, 'coffee_cup'],
        ['apple', 'orange', 'pear', 2, 3.80, 'coffee_cup']
    ]

#Here you can select the important fields 
key = lambda i: (i[0],i[2])

l.sort(key=key)
grp = itertools.groupby(l, key=key)
#Look at itertools documentation
grouped = (list(j) for i,j in grp)

for i in grouped:
    if len(i) == 1:
        i[0].append(0)
    else: #You want duplicates to start from 1
        for pos, item in enumerate(i, 1):
            item.append(pos)

#Just a little loop for flattening the list
result = [] 
for i in grouped:
    for j in i:
        result.append(j)

print(result)

输出:

[['apple', 'orange', 'kiwi', 3, 1.8, 'banana', 0],
 ['apple', 'window', 'pear', 2, 1.55, 'banana', 1],
 ['apple', 'orange', 'pear', 2, 0.8, 'coffee_cup', 2],
 ['apple', 'orange', 'pear', 2, 3.8, 'coffee_cup', 3],
 ['apple', 'envelope', 'star_fruit', 2, 1.55, 'banana', 0]]
相关问题