我正在寻找一种解决以下问题的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的书。
答案 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]]