Fastest way to remove duplicates from a list of comparable, unhashable items
如果我只知道列表元素可以排序,那么如何从列表中删除重复项?(我也不关心列表中项目的顺序。)
现有的问题,比如如何从python列表中删除重复项并保持顺序?或者,删除列表中的重复项需要使用集合,即要求列表中的项是可哈希的。在我的例子中,哈希性并不能保证。
- 对于"如何从列表中删除重复项"这样的问题来说,这是一个荒谬的要求——列表可以包含任何内容,因此它确实不能回答问题,是吗?
- @提格霍克特3请重新打开。我花了很长时间才找到这个答案,约翰·拉罗伊的答案太棒了!
- 哇,当第三个答案落下时,那条评论就被掩埋了,而对这条评论的评论才是答案。但不管怎样。
- 让一个python集完成所有的工作怎么样?list(set(list))集合是否需要可哈希元素?
- 是的,集合需要可哈希元素。set([{'a': 2}])抛出TypeError: unhashable type: 'dict'。如果我想从听写列表中删除重复项,我就不能使用那些标记为"重复项"的用户。
在Python中,对已经排序的列表进行排序的调用的开销可以忽略不计。增加额外的复杂性和有人意外地将错误的参数传递给函数的可能性是不值得的。
1 2 3 4 5 6 7
| from itertools import groupby
def remove_duplicates(data):
''' Remove duplicates from the data (normally a list).
The data must be sortable and have an equality operator
'''
data = sorted(data)
return [k for k, v in groupby(data)] |
- 好极了!我没有意识到Itertools Groupby可以这样使用,这是Briliant!看看groupby代码,它看起来"k"甚至不需要是可哈希的,这正是我想要的。
- 由于问题是关于"最快"的问题,因此可能需要将比较结果添加到索赔的后面。
编辑:请看约翰·拉罗伊的回答。
同样,这个解决方案只适用于可排序的列表。如果预先对其排序(实际上只需要对对象进行分组),可以将sort设置为false,然后只需要比较运算符。
1 2 3 4 5 6 7 8 9 10 11 12 13
| def remove_duplicates(data, sort=True):
''' Remove duplicates from the data (normally a list).
The data must be sortable and have an equality operator
'''
if not data:
return data
if sort:
data = sorted(data)
out = [data[0]]
for i, n in enumerate(data[1:]):
if data[i] != n:
out.append(n)
return out |
- 您也可以定义__hash__,这样就可以使用set()。
- 粗略的测试,但你的标题说"最快",我似乎得到更快的结果使用from itertools import izip_longest和out = [x for (x,y) in izip_longest(data,data[1:]) if x != y]。给出范围(1000)*3,所以所有内容都是三倍化的,并预先排序,运行10000次迭代,使用代码大约需要5秒,使用Izip_最长需要3.3秒,结果列表==相同。
- 这大致上就是这个用户在一个重复的线程中建议的,但是a)与numpy无关,b)我怀疑他们有一个错误,如果最后的列表项不是重复的,那么它会丢失;c)他们使用的是内置的zip,当我尝试它时,它没有相同的加速方式。(也许在python 3中是这样的?)iTertools版本用无填充较短的列表,并修复了最后一个项目错误,我认为,而且速度更快。
- 迭代一个额外的项目比复制一个切片data[1:]要快。
- @tessellatingheckler-python 3的zip()、itertools.zip_longest()、range()等已经产生了懒惰的对象,而不是急于创建list。
- @Johnlarooy"更快地迭代一个额外的项目"是什么意思?如果我在python中用索引计数器从1开始计算列表,它会变得非常慢…
- @Tigerhawkt3为易变项定义散列将是一个相当糟糕的主意。
- @约翰洛伊,你说得对。实际上,我应该使用来自itertools的islice
- @我喜欢这个。我敢打赌约翰·拉鲁伊打败了我们两个:还有,你忘了分类。
- @johnlarooy的答案(在我的同一个测试块中)与我的答案大致相同,但如果他只在被请求时调用sorted(),那么在预先排序的测试块上,它会快15%。