【问题标题】:Removing duplicates in lists删除列表中的重复项
【发布时间】:2011-12-19 04:02:39
【问题描述】:

我几乎需要编写一个程序来检查列表是否有任何重复项,如果有,它会删除它们并返回一个新列表,其中包含未重复/删除的项目。这是我所拥有的,但老实说我不知道​​该怎么做。

def remove_duplicates():
    t = ['a', 'b', 'c', 'd']
    t2 = ['a', 'c', 'd']
    for t in t2:
        t.append(t.remove())
    return t

【问题讨论】:

标签: python algorithm list duplicates intersection


【解决方案1】:

获取唯一项目集合的常用方法是使用set。集合是无序不同对象的集合。要从任何可迭代对象创建集合,您只需将其传递给内置的 set() 函数即可。如果您以后再次需要一个真实的列表,您可以类似地将集合传递给list() 函数。

以下示例应涵盖您尝试做的任何事情:

>>> t = [1, 2, 3, 1, 2, 5, 6, 7, 8]
>>> t
[1, 2, 3, 1, 2, 5, 6, 7, 8]
>>> list(set(t))
[1, 2, 3, 5, 6, 7, 8]
>>> s = [1, 2, 3]
>>> list(set(t) - set(s))
[8, 5, 6, 7]

从示例结果可以看出,原来的顺序没有维护。如上所述,集合本身是无序的集合,因此失去了顺序。将集合转换回列表时,会创建任意顺序。

维护秩序

如果顺序对您很重要,那么您将不得不使用不同的机制。一个非常常见的解决方案是依靠OrderedDict 在插入过程中保持键的顺序:

>>> from collections import OrderedDict
>>> list(OrderedDict.fromkeys(t))
[1, 2, 3, 5, 6, 7, 8]

Starting with Python 3.7,内置字典也保证保持插入顺序,所以如果你在 Python 3.7 或更高版本(或 CPython 3.6)上也可以直接使用它:

>>> list(dict.fromkeys(t))
[1, 2, 3, 5, 6, 7, 8]

请注意,这可能会产生一些开销,即首先创建字典,然后从中创建列表。如果您实际上不需要保留顺序,通常最好使用集合,特别是因为它为您提供了更多操作。查看this question 了解更多详细信息以及在删除重复项时保留顺序的替代方法。


最后请注意,setOrderedDict/dict 解决方案都要求您的项目可散列。这通常意味着它们必须是不可变的。如果您必须处理不可散列的项目(例如列表对象),那么您将不得不使用一种缓慢的方法,在这种方法中,您基本上必须将每个项目与嵌套循环中的每个其他项目进行比较。

【讨论】:

  • 把这个加到例子中,t = [3, 2, 1, 1, 2, 5, 6, 7, 8],区别就很明显了!
  • "...首先创建字典的开销...如果您实际上不需要保留顺序,最好使用集合。" - 我对此进行了分析,因为我很好奇它是否真的是真的。我的时间显示确实该集合稍微快一点:每个循环(集合)1.12 µs vs 每个循环(dict)1.53 µs,超过 1M 循环,绝对时间差在 1M 迭代中约为 4s。因此,如果您在紧密的内部循环中执行此操作,您可能会关心,否则可能不会。
  • @millerdev 我本来想说“开销不仅仅意味着时间”,但后来我检查了一下,似乎键控字典在内存中实际上比设置相同的元素。至少在当前版本的 Python 中。这真的很令人惊讶——但是,是的,这是一个很好的观点!谢谢!
  • 这解决了 unhashable 类型(其中 t 是字典列表)的问题:[dict(d) for d in set([frozenset(i.items()) for i in t])]
  • @BigDreamz dict.fromkeys() 在线性时间内创建一个字典,list() 将在线性时间内从中创建一个列表。
【解决方案2】:

在 Python 2.7 中,从可迭代项中删除重复项同时保持其原始顺序的新方法是:

>>> from collections import OrderedDict
>>> list(OrderedDict.fromkeys('abracadabra'))
['a', 'b', 'r', 'c', 'd']

在 Python 3.5 中,OrderedDict 具有 C 实现。我的时间安排表明,这现在是 Python 3.5 各种方法中最快和最短的方法。

在 Python 3.6 中,常规 dict 变得有序且紧凑。 (此功能适用于 CPython 和 PyPy,但可能不存在于其他实现中)。这为我们提供了一种在保持顺序的同时进行重复数据删除的最快方法:

>>> list(dict.fromkeys('abracadabra'))
['a', 'b', 'r', 'c', 'd']

在 Python 3.7 中,保证常规 dict 在所有实现中都是有序的。 因此,最短和最快的解决方案是:

>>> list(dict.fromkeys('abracadabra'))
['a', 'b', 'r', 'c', 'd']

【讨论】:

【解决方案3】:

这是一个单行代码:list(set(source_list)) 可以解决问题。

set 是不可能有重复的东西。

更新:保持顺序的方法是两行:

from collections import OrderedDict
OrderedDict((x, True) for x in source_list).keys()

这里我们使用OrderedDict 记住键的插入顺序,并且在更新特定键的值时不会更改它的事实。我们插入True 作为值,但我们可以插入任何东西,只是不使用值。 (set 的工作方式很像 dict,但也忽略了值。)

【讨论】:

  • @AdrianKeister:这是真的。有些对象具有合理的相等语义但不可散列,例如列表。 OTOH,如果我们不能有一个像 hastable 这样的捷径,我们最终会得到一个二次算法,将每个元素与所有当前已知的唯一元素进行比较。这对于短输入是完全可以的,尤其是在有很多重复的情况下。
  • 正确,完全正确。如果您考虑到这个非常常见的用例,我认为您的答案质量会更高。
【解决方案4】:
>>> t = [1, 2, 3, 1, 2, 5, 6, 7, 8]
>>> t
[1, 2, 3, 1, 2, 5, 6, 7, 8]
>>> s = []
>>> for i in t:
       if i not in s:
          s.append(i)
>>> s
[1, 2, 3, 5, 6, 7, 8]

【讨论】:

  • 请注意,此方法在 O(n^2) 时间内有效,因此在大型列表上非常慢。
【解决方案5】:

如果您不关心订单,只需这样做:

def remove_duplicates(l):
    return list(set(l))

set 保证没有重复项。

【讨论】:

    【解决方案6】:

    要创建一个新列表,保留L 中重复项的第一个元素的顺序:

    newlist = [ii for n,ii in enumerate(L) if ii not in L[:n]]
    

    例如:如果L = [1, 2, 2, 3, 4, 2, 4, 3, 5],那么newlist将是[1, 2, 3, 4, 5]

    这会在添加之前检查每个新元素之前没有出现在列表中。 它也不需要导入。

    【讨论】:

    • 这有 O(n ^ 2) 的时间复杂度。 setOrderedDict 的答案可能具有较低的摊销时间复杂度。
    • 我在我的代码中使用了这个解决方案,效果很好,但我认为它很耗时
    • @blubberdiblub 你能解释一下 set 和 OrderedDict 中存在哪些代码效率更高的机制可以减少它们的耗时吗? (不包括加载它们的开销)
    • @iliasiliadis setdict 的通常实现使用哈希或(某种形式的平衡)树。您必须考虑构建 setdict 并在其中搜索(多次),但它们的摊销复杂度通常仍低于 O(n ^ 2) 。简单来说,“摊销”意味着平均(他们可能有比平均情况更复杂的最坏情况)。这仅在您拥有大量项目时才相关。
    【解决方案7】:

    还有使用 Pandas 和 Numpy 的解决方案。它们都返回 numpy 数组,所以如果你想要一个列表,你必须使用函数 .tolist()

    t=['a','a','b','b','b','c','c','c']
    t2= ['c','c','b','b','b','a','a','a']
    

    熊猫解决方案

    使用熊猫函数unique()

    import pandas as pd
    pd.unique(t).tolist()
    >>>['a','b','c']
    pd.unique(t2).tolist()
    >>>['c','b','a']
    

    Numpy 解决方案

    使用 numpy 函数unique()

    import numpy as np
    np.unique(t).tolist()
    >>>['a','b','c']
    np.unique(t2).tolist()
    >>>['a','b','c']
    

    请注意,numpy.unique() 也会对值进行排序。所以列表t2 是排序返回的。如果您想保留订单,请使用 this answer:

    _, idx = np.unique(t2, return_index=True)
    t2[np.sort(idx)].tolist()
    >>>['c','b','a']
    

    与其他解决方案相比,该解决方案并不那么优雅,但是,与 pandas.unique() 相比,numpy.unique() 还允许您检查嵌套数组在一个选定的轴上是否唯一。

    【讨论】:

    • 这会将列表转换为 numpy 数组,这是一团糟,不适用于字符串。
    • @user227666 感谢您的评论,但事实并非如此,它甚至可以使用字符串,如果您想获取列表,可以添加 .tolist...
    • 我认为这有点像试图用大锤杀死一只蜜蜂。工作,当然!但是,仅仅为此目的导入一个库可能有点矫枉过正,不是吗?
    • 2020 年最佳答案@DebosmitRay 我希望你改变主意,每次可以使用 numpy / pandas
    【解决方案8】:

    今天,一位同事已将接受的答案作为其代码的一部分发送给我进行代码审查。 虽然我当然很佩服这个答案的优雅,但我对这个表现并不满意。 我已经尝试过这个解决方案(我使用 set 来减少查找时间)

    def ordered_set(in_list):
        out_list = []
        added = set()
        for val in in_list:
            if not val in added:
                out_list.append(val)
                added.add(val)
        return out_list
    

    为了比较效率,我使用了 100 个整数的随机样本 - 62 个是唯一的

    from random import randint
    x = [randint(0,100) for _ in xrange(100)]
    
    In [131]: len(set(x))
    Out[131]: 62
    

    这是测量结果

    In [129]: %timeit list(OrderedDict.fromkeys(x))
    10000 loops, best of 3: 86.4 us per loop
    
    In [130]: %timeit ordered_set(x)
    100000 loops, best of 3: 15.1 us per loop
    

    那么,如果从解决方案中删除 set 会发生什么?

    def ordered_set(inlist):
        out_list = []
        for val in inlist:
            if not val in out_list:
                out_list.append(val)
        return out_list
    

    结果没有OrderedDict那么差,但还是原解的3倍以上

    In [136]: %timeit ordered_set(x)
    10000 loops, best of 3: 52.6 us per loop
    

    【讨论】:

    • 很好地使用设置快速查找来加速循环比较。如果顺序无关紧要,则 list(set(x)) 仍然比这快 6 倍
    • @Joop,这是我向同事提出的第一个问题——顺序很重要;否则,这将是微不足道的问题
    • 有序集优化版,感兴趣的朋友可以参考:def unique(iterable):;seen = set(); seen_add = seen.add; return [item for item in iterable if not item in seen and not seen_add(item)]
    【解决方案9】:

    在这个答案中,将有两个部分:两个独特的解决方案,以及特定解决方案的速度图。

    删除重复项

    这些答案中的大多数只删除 hashable 的重复项目,但这个问题并不意味着它不仅需要 hashable 项目,这意味着我会提供一些不需要 hashable 项的解决方案。

    collections.Counter 是标准库中一个强大的工具,可以完美地解决这个问题。只有另一种解决方案甚至包含 Counter 。但是,该解决方案也仅限于 hashable 键。

    为了在 Counter 中允许不可散列的键,我做了一个 Container 类,它会尝试获取对象的默认散列函数,但如果失败,它会尝试其标识函数。它还定义了一个 eq 和一个 hash 方法。这应该足以在我们的解决方案中允许 unhashable 项。不可散列的对象将被视为可散列。然而,这个散列函数对不可散列的对象使用身份,这意味着两个同样不可散列的对象将不起作用。我建议您覆盖它,并将其更改为使用等效可变类型的哈希(例如,如果 my_list 是列表,则使用 hash(tuple(my_list)))。

    我也提出了两个解决方案。另一种保持项目顺序的解决方案,使用名为“OrderedCounter”的 OrderedDict 和 Counter 的子类。现在,这里是函数:

    from collections import OrderedDict, Counter
    
    class Container:
        def __init__(self, obj):
            self.obj = obj
        def __eq__(self, obj):
            return self.obj == obj
        def __hash__(self):
            try:
                return hash(self.obj)
            except:
                return id(self.obj)
    
    class OrderedCounter(Counter, OrderedDict):
         'Counter that remembers the order elements are first encountered'
    
         def __repr__(self):
             return '%s(%r)' % (self.__class__.__name__, OrderedDict(self))
    
         def __reduce__(self):
             return self.__class__, (OrderedDict(self),)
        
    def remd(sequence):
        cnt = Counter()
        for x in sequence:
            cnt[Container(x)] += 1
        return [item.obj for item in cnt]
    
    def oremd(sequence):
        cnt = OrderedCounter()
        for x in sequence:
            cnt[Container(x)] += 1
        return [item.obj for item in cnt]
    

    remd 是无序排序,oremd 是有序排序。您可以清楚地分辨出哪个更快,但无论如何我都会解释。无序排序稍微快一些,因为它不存储项目的顺序。

    现在,我还想展示每个答案的速度比较。所以,我现在就这样做。

    哪个函数最快?

    为了删除重复项,我从几个答案中收集了 10 个函数。我计算了每个函数的速度,并使用 matplotlib.pyplot 将其放入图表中。

    我将其分为三轮绘图。 hashable 是可以散列的任何对象,unhashable 是任何不能散列的对象。有序序列是保持顺序的序列,无序序列不保持顺序。现在,这里还有一些术语:

    Unordered Hashable 适用于任何删除重复项的方法,不一定要保持顺序。它不一定适用于不可散列的数据,但它可以。

    Ordered Hashable 适用于保持列表中项目顺序的任何方法,但它不一定适用于 unhashables,但它可以。

    Ordered Unhashable 是保持列表中项目顺序的任何方法,并且适用于 unhashables。

    在 y 轴上是花费的秒数。

    x 轴上是应用函数的数字。

    我使用以下理解为无序哈希和有序哈希生成序列:[list(range(x)) + list(range(x)) for x in range(0, 1000, 10)]

    对于有序的 unhashable:[[list(range(y)) + list(range(y)) for y in range(x)] for x in range(0, 1000, 10)]

    请注意,该范围内有一个 step,因为如果没有它,这将花费 10 倍的时间。还因为在我个人看来,我认为它可能看起来更容易阅读。

    还要注意图例中的键是我试图猜测的功能实现中最重要的部分。至于什么功能最差或最好?图表不言自明。

    解决了,下面是图表。

    无序哈希

    (放大)

    有序哈希

    (放大)

    有序不可散列

    (放大)

    【讨论】:

    • 难以阅读。最好在底部有一个顶部列表,并包含结果。因此,对于无序哈希:不要使用: #- ii for n,ii in enumerate(seq) if ii not in seq[:n] #- cnt = Counter(); cnt[Container(x)] += 1 #- cnt = OrderedCounter(); cnt[Container(x)) += 1 #- if i not in new for i in seq. 更好的使用: #- list(set(seq)) #- dict.fromkeys(seq) #- added = set(); for in seq: if not val in added #- OrderedDict.fromkeys(seq) #- OrderedDict((x, True) for x in seq).keys() #- functools.reduce(lambda r, v: v in r[ 1] and r or ... or ..., ([], set[]))[0]
    【解决方案10】:

    另一种做法:

    >>> seq = [1,2,3,'a', 'a', 1,2]
    >> dict.fromkeys(seq).keys()
    ['a', 1, 2, 3]
    

    【讨论】:

    • 请注意,在现代 Python 版本中(我认为是 2.7+,但我记不太清了),keys() 返回一个字典视图对象,而不是一个列表。
    【解决方案11】:

    简单易行:

    myList = [1, 2, 3, 1, 2, 5, 6, 7, 8]
    cleanlist = []
    [cleanlist.append(x) for x in myList if x not in cleanlist]
    

    输出:

    >>> cleanlist 
    [1, 2, 3, 5, 6, 7, 8]
    

    【讨论】:

    • 仍然是二次复杂度 - in 是 O(n) 运算,您的 cleanlist 最多有 n 数字 => 最坏情况 ~O(n^2)
    • 列表推导不应该用于副作用。
    【解决方案12】:

    答案很晚。如果您不关心列表顺序,可以使用 *arg 扩展和 set 唯一性来删除欺骗,即:

    l = [*{*l}]
    

    Demo

    【讨论】:

    • 很好......唯一的问题是它非常聪明,以至于您必须添加评论才能说出它的作用。
    【解决方案13】:

    我的列表中有一个字典,所以我不能使用上述方法。我得到了错误:

    TypeError: unhashable type:
    

    因此,如果您关心 订单 和/或某些商品是 不可散列。那么您可能会发现这很有用:

    def make_unique(original_list):
        unique_list = []
        [unique_list.append(obj) for obj in original_list if obj not in unique_list]
        return unique_list
    

    有些人可能认为具有副作用的列表理解不是一个好的解决方案。这是另一种选择:

    def make_unique(original_list):
        unique_list = []
        map(lambda x: unique_list.append(x) if (x not in unique_list) else False, original_list)
        return unique_list
    

    【讨论】:

    • map 具有副作用比具有副作用的 listcomp 更具误导性。此外,lambda x: unique_list.append(x) 只是通过unique_list.append 的一种更笨重、更慢的方式。
    • 在一行中追加元素的非常有用的方法,谢谢!
    • @ZLNK 请不要使用它。除了在概念上难看之外,它的效率也极低,因为您实际上创建了一个可能很大的列表并将其丢弃,只是为了执行基本的迭代。
    【解决方案14】:

    如果您想保留顺序,并且不使用任何外部模块,这是一种简单的方法:

    >>> t = [1, 9, 2, 3, 4, 5, 3, 6, 7, 5, 8, 9]
    >>> list(dict.fromkeys(t))
    [1, 9, 2, 3, 4, 5, 6, 7, 8]
    

    注意:此方法保留了出现的顺序,因此,如上所示,9 将在一个之后,因为它是第一次出现。然而,这和你做的结果是一样的

    from collections import OrderedDict
    ulist=list(OrderedDict.fromkeys(l))
    

    但它更短,运行速度更快。

    这是有效的,因为每次fromkeys 函数尝试创建一个新键时,如果该值已经存在,它将简单地覆盖它。但是,这根本不会影响字典,因为fromkeys 创建了一个字典,其中所有键的值都为None,因此它可以有效地消除所有重复项。

    【讨论】:

    • 也可以试试here
    【解决方案15】:

    到目前为止,我在这里看到的所有保持顺序的方法要么使用简单比较(最多 O(n^2) 时间复杂度),要么使用重量级 OrderedDicts/set+list 组合仅限于可散列的输入。这是一个与哈希无关的 O(nlogn) 解决方案:

    更新添加了 key 参数、文档和 Python 3 兼容性。

    # from functools import reduce <-- add this import on Python 3
    
    def uniq(iterable, key=lambda x: x):
        """
        Remove duplicates from an iterable. Preserves order. 
        :type iterable: Iterable[Ord => A]
        :param iterable: an iterable of objects of any orderable type
        :type key: Callable[A] -> (Ord => B)
        :param key: optional argument; by default an item (A) is discarded 
        if another item (B), such that A == B, has already been encountered and taken. 
        If you provide a key, this condition changes to key(A) == key(B); the callable 
        must return orderable objects.
        """
        # Enumerate the list to restore order lately; reduce the sorted list; restore order
        def append_unique(acc, item):
            return acc if key(acc[-1][1]) == key(item[1]) else acc.append(item) or acc 
        srt_enum = sorted(enumerate(iterable), key=lambda item: key(item[1]))
        return [item[1] for item in sorted(reduce(append_unique, srt_enum, [srt_enum[0]]))] 
    

    【讨论】:

    • 然而,这个解决方案需要可订购的元素。我将使用它来唯一化我的列表:tuple() 列表和散列它们很痛苦。 | | | | - 一般来说,hash过程所花费的时间与整个数据的大小成正比,而这种解决方案需要时间O(nlog(n)),仅取决于列表的长度。
    • 我认为基于集合的方法与排序 + 唯一性检测同样便宜 (O(n log n)),或者更便宜。 (不过,这种方法会更好地并行化。)它也不完全保留初始顺序,但它提供了可预测的顺序。
    • @9000 确实如此。我从来没有提到基于哈希表的方法的时间复杂度,这显然是 O(n)。在这里,您可以找到许多包含哈希表的答案。但是,它们不是通用的,因为它们要求对象是可散列的。此外,它们更占用内存。
    • 花时间阅读和理解这个答案。当您不使用索引时,枚举是否有意义? reduce() 已经在处理排序集合 srt_enum,你为什么再次申请 sorted
    • @Brayoni 第一个排序用于对相等的值进行分组,第二个排序用于恢复初始顺序。需要枚举来跟踪原始的相对顺序。
    【解决方案16】:

    你也可以这样做:

    >>> t = [1, 2, 3, 3, 2, 4, 5, 6]
    >>> s = [x for i, x in enumerate(t) if i == t.index(x)]
    >>> s
    [1, 2, 3, 4, 5, 6]
    

    上述工作的原因是index 方法只返回元素的第一个索引。重复元素具有更高的索引。参考here

    list.index(x[, start[, end]])
    返回列表中从零开始的索引 值为 x 的第一项。如果没有,则引发 ValueError 这样的项目。

    【讨论】:

    • 这是非常低效的。 list.index 是一个线性时间运算,使您的解成为二次方。
    • 你是对的。但我也相信,很明显,该解决方案旨在成为一种保持秩序的单线。其他所有东西都已经在这里了。
    【解决方案17】:

    从列表中删除重复项的最佳方法是使用 Python 中提供的 set() 函数,再次将该 set 转换为列表

    In [2]: some_list = ['a','a','v','v','v','c','c','d']
    In [3]: list(set(some_list))
    Out[3]: ['a', 'c', 'd', 'v']
    

    【讨论】:

    • @MeetZaveri 很高兴!
    • 实例化新列表和集合不是免费的。如果我们快速连续多次执行此操作(即在一个非常紧凑的循环中)并且列表非常小,会发生什么?
    【解决方案18】:

    您可以使用set 删除重复项:

    mylist = list(set(mylist))
    

    但请注意,结果将是无序的。如果这是一个问题:

    mylist.sort()
    

    【讨论】:

    • 你可以这样做:mylist = sorted(list(set(mylist)))
    【解决方案19】:

    尝试使用集合:

    import sets
    t = sets.Set(['a', 'b', 'c', 'd'])
    t1 = sets.Set(['a', 'b', 'c'])
    
    print t | t1
    print t - t1
    

    【讨论】:

      【解决方案20】:

      使用排序保留减少变体:

      假设我们有列表:

      l = [5, 6, 6, 1, 1, 2, 2, 3, 4]
      

      减少变体(低效):

      >>> reduce(lambda r, v: v in r and r or r + [v], l, [])
      [5, 6, 1, 2, 3, 4]
      

      快 5 倍但更复杂

      >>> reduce(lambda r, v: v in r[1] and r or (r[0].append(v) or r[1].add(v)) or r, l, ([], set()))[0]
      [5, 6, 1, 2, 3, 4]
      

      解释:

      default = (list(), set())
      # user list to keep order
      # use set to make lookup faster
      
      def reducer(result, item):
          if item not in result[1]:
              result[0].append(item)
              result[1].add(item)
          return result
      
      reduce(reducer, l, default)[0]
      

      【讨论】:

        【解决方案21】:

        一种更好的方法可能是,

        import pandas as pd
        
        myList = [1, 2, 3, 1, 2, 5, 6, 7, 8]
        cleanList = pd.Series(myList).drop_duplicates().tolist()
        print(cleanList)
        
        #> [1, 2, 3, 5, 6, 7, 8]
        

        订单仍然保留。

        【讨论】:

        • 虽然这可能效果很好,但为此目的使用像 pandas 这样的繁重库似乎有点过头了。
        【解决方案22】:

        您可以使用以下功能:

        def rem_dupes(dup_list): 
            yooneeks = [] 
            for elem in dup_list: 
                if elem not in yooneeks: 
                    yooneeks.append(elem) 
            return yooneeks
        

        示例

        my_list = ['this','is','a','list','with','dupicates','in', 'the', 'list']
        

        用法:

        rem_dupes(my_list)
        

        ['this', 'is', 'a', 'list', 'with', 'dupicates', 'in', 'the']

        【讨论】:

        • 不适合大型列表,因为它会创建重复项。
        • @ingyhere OP 没有提出任何建议:大型列表。每种类型的实现都有一个总是权衡,因此每个答案必须默认为“最具可扩展性”的前提是错误的。
        【解决方案23】:

        还有很多其他答案提出了不同的方法来做到这一点,但它们都是批处理操作,其中一些会丢弃原始订单。根据您的需要,这可能没问题,但是如果您想按每个值的第一个实例的顺序迭代这些值,并且您想即时删除重复项而不是一次全部删除,您可以使用这个生成器:

        def uniqify(iterable):
            seen = set()
            for item in iterable:
                if item not in seen:
                    seen.add(item)
                    yield item
        

        这会返回一个生成器/迭代器,因此您可以在任何可以使用迭代器的地方使用它。

        for unique_item in uniqify([1, 2, 3, 4, 3, 2, 4, 5, 6, 7, 6, 8, 8]):
            print(unique_item, end=' ')
        
        print()
        

        输出:

        1 2 3 4 5 6 7 8
        

        如果您确实想要list,您可以这样做:

        unique_list = list(uniqify([1, 2, 3, 4, 3, 2, 4, 5, 6, 7, 6, 8, 8]))
        
        print(unique_list)
        

        输出:

        [1, 2, 3, 4, 5, 6, 7, 8]
        

        【讨论】:

        • seen = set(iterable); for item in seen: yield item 几乎可以肯定更快。 (我没有尝试过这种具体情况,但这是我的猜测。)
        • @dylnmc,这是一个批处理操作,它也失去了排序。我的回答专门针对即时和首次出现的顺序。 :)
        【解决方案24】:

        不使用集合

        data=[1, 2, 3, 1, 2, 5, 6, 7, 8]
        uni_data=[]
        for dat in data:
            if dat not in uni_data:
                uni_data.append(dat)
        
        print(uni_data) 
        

        【讨论】:

          【解决方案25】:

          Python 内置类型的魔力

          在python中,这样的复杂情况很容易处理,只需要python的内置类型即可。

          让我告诉你怎么做!

          方法一:一般情况

          删除列表中重复元素并保持排序顺序的方式(1行代码

          line = [1, 2, 3, 1, 2, 5, 6, 7, 8]
          new_line = sorted(set(line), key=line.index) # remove duplicated element
          print(new_line)
          

          你会得到结果

          [1, 2, 3, 5, 6, 7, 8]
          

          方法二:特殊情况

          TypeError: unhashable type: 'list'
          

          处理不可散列的特殊情况(3行代码

          line=[['16.4966155686595', '-27.59776154691', '52.3786295521147']
          ,['16.4966155686595', '-27.59776154691', '52.3786295521147']
          ,['17.6508629295574', '-27.143305738671', '47.534955022564']
          ,['17.6508629295574', '-27.143305738671', '47.534955022564']
          ,['18.8051102904552', '-26.688849930432', '42.6912804930134']
          ,['18.8051102904552', '-26.688849930432', '42.6912804930134']
          ,['19.5504702331098', '-26.205884452727', '37.7709192714727']
          ,['19.5504702331098', '-26.205884452727', '37.7709192714727']
          ,['20.2929416861422', '-25.722717575124', '32.8500163147157']
          ,['20.2929416861422', '-25.722717575124', '32.8500163147157']]
          
          tuple_line = [tuple(pt) for pt in line] # convert list of list into list of tuple
          tuple_new_line = sorted(set(tuple_line),key=tuple_line.index) # remove duplicated element
          new_line = [list(t) for t in tuple_new_line] # convert list of tuple into list of list
          
          print (new_line)
          

          你会得到结果:

          [
            ['16.4966155686595', '-27.59776154691', '52.3786295521147'], 
            ['17.6508629295574', '-27.143305738671', '47.534955022564'], 
            ['18.8051102904552', '-26.688849930432', '42.6912804930134'], 
            ['19.5504702331098', '-26.205884452727', '37.7709192714727'], 
            ['20.2929416861422', '-25.722717575124', '32.8500163147157']
          ]
          

          因为元组是可散列的,你可以很容易地在列表和元组之间转换数据

          【讨论】:

            【解决方案26】:

            这个人关心订单,没有太多麻烦(OrderdDict 和其他人)。可能不是最 Pythonic 的方式,也不是最短的方式,但可以做到:

            def remove_duplicates(item_list):
                ''' Removes duplicate items from a list '''
                singles_list = []
                for element in item_list:
                    if element not in singles_list:
                        singles_list.append(element)
                return singles_list
            

            【讨论】:

            • 1.你永远不应该隐藏内置名称(至少和list 一样重要); 2. 你的方法扩展性极差:list 中的元素数量是二次方的。
            • 1.正确,但这是一个例子; 2. 正确,这正是我提供它的原因。此处发布的所有解决方案都有利有弊。有些牺牲了简单性或秩序,我的牺牲了可扩展性。
            【解决方案27】:

            下面的代码很容易删除列表中的重复项

            def remove_duplicates(x):
                a = []
                for i in x:
                    if i not in a:
                        a.append(i)
                return a
            
            print remove_duplicates([1,2,2,3,3,4])
            

            它返回 [1,2,3,4]

            【讨论】:

            • 如果您不关心订单,那么这需要更长的时间。 list(set(..))(超过 100 万次通过)将比这个解决方案快大约 10 秒 - 而这种方法大约需要 12 秒,list(set(..)) 只需要大约 2 秒!
            • @dylnmc 这也是一个明显较旧的answer的副本
            【解决方案28】:

            这是与回复中列出的其他人相比最快的 Pythonic 解决方案。

            使用短路评估的实现细节允许使用足够快的列表推导。 visited.add(item) 总是返回None 作为结果,它被评估为False,所以or 的右侧总是这样的表达式的结果。

            自己计时

            def deduplicate(sequence):
                visited = set()
                adder = visited.add  # get rid of qualification overhead
                out = [adder(item) or item for item in sequence if item not in visited]
                return out
            

            【讨论】:

              【解决方案29】:

              使用 set

              a = [0,1,2,3,4,3,3,4]
              a = list(set(a))
              print a
              

              使用独特

              import numpy as np
              a = [0,1,2,3,4,3,3,4]
              a = np.unique(a).tolist()
              print a
              

              【讨论】:

                【解决方案30】:

                Python 3 中非常简单的方法:

                >>> n = [1, 2, 3, 4, 1, 1]
                >>> n
                [1, 2, 3, 4, 1, 1]
                >>> m = sorted(list(set(n)))
                >>> m
                [1, 2, 3, 4]
                

                【讨论】:

                • sorted(list(...)) 是多余的(sorted 已经隐式将其参数转换为新的list,对其进行排序,然后返回新的list,因此使用这两种方法意味着制作一个不必要的临时@987654326 @)。如果不需要对结果进行排序,请仅使用list,如果需要对结果进行排序,请仅使用sorted
                猜你喜欢
                • 1970-01-01
                • 2011-10-04
                • 2014-09-30
                • 2011-01-13
                • 2021-04-02
                相关资源
                最近更新 更多