【问题标题】:Fastest way to remove duplicates from a list of comparable, unhashable items [duplicate]从可比较的、不可散列的项目列表中删除重复项的最快方法 [重复]
【发布时间】:2015-12-18 19:20:41
【问题描述】:

如果我只知道列表元素可以排序,如何从列表中删除重复项? (我也不关心列表中项目的顺序。)

How to remove duplicates from Python list and keep order?Removing duplicates in lists 等现有问题需要使用集合,即要求列表中的项目是可散列的。 在我的情况下,哈希性不是保证。

【问题讨论】:

  • 对于“如何从列表中删除重复项”这个问题是一个荒谬的要求——一个列表可以包含任何东西,所以它真的不能回答这个问题,是吗?
  • @TigerhawkT3 请重新打开。我花了很长时间才找到这个,John La Rooy 的回答太棒了!
  • 哇,该评论作为第三个答案被埋没了,实际上评论的评论就是答案。但无论如何。
  • 让 Python 集完成所有工作怎么样? list(set(list)) 集合是否需要可散列的元素?
  • 是的,一个集合需要可散列的元素。 set([{'a': 2}]) 抛出 TypeError: unhashable type: 'dict'。如果我想从字典列表中删除重复项,我不能使用那些用户标记的“重复项”。

标签: python list duplicates


【解决方案1】:

编辑:请参阅 John La Rooy 的答案以获得更好的答案。

同样,该解决方案仅适用于可排序列表。如果您对其进行了预排序(实际上对象只需要分组),您可以设置 sort=False,然后它只需要比较运算符。

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_longestout = [x for (x,y) in izip_longest(data,data[1:]) if x != y] 获得更快的结果。给定 range(1000) * 3,所以所有内容都是三次重复的,并且是预先排序的,并运行 10,000 次迭代,您的代码大约需要 5 秒,而 izip_longest 需要 3.3 秒,结果列表 == 相同。
  • 这大致是this user 在其中一个重复线程中建议的内容,但是 a) 与 numpy 无关,b) 我怀疑他们有一个错误,如果它不是重复的,则缺少最终列表项,并且c)他们使用的是内置的 zip,当我尝试它时,它没有相同的加速。 (也许在 Python 3 中会这样?)我认为,itertools 版本用 None 填充较短的列表并修复了最后一项错误,并且速度更快。
  • 迭代一个额外的项目比复制切片data[1:]
  • @TessellatingHeckler - Python 3 的zip()itertools.zip_longest()range() 等已经产生惰性对象,而不是急切地创建list
【解决方案2】:

在已经排序的列表上调用 sorted 在 Python 中的开销可以忽略不计。增加额外的复杂性和有人不小心将错误的参数传递给函数的可能性真的不值得

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 可以以这种方式使用,这太棒了!查看 groupby 代码,看起来“k”甚至不需要是可散列的,这正是我想要的。
  • 由于问题是在询问“最快”,因此可能应该添加比较结果来支持声明。
猜你喜欢
  • 2010-12-13
  • 2020-04-05
  • 1970-01-01
  • 1970-01-01
  • 2014-04-20
  • 2015-08-02
  • 1970-01-01
  • 2011-04-05
  • 1970-01-01
相关资源
最近更新 更多