我如何检查一个列表是否有任何重复,并返回一个没有重复的新列表?


当前回答

如果列表是有序的,则可以使用以下方法对其进行迭代,跳过重复的值。这对于处理内存消耗低的大列表特别有用,可以避免构建dict或set的成本:

def uniq(iterator):
    prev = None
    for item in iterator:
        if item != prev:
            prev = item
            yield item

然后:

for item in uniq([1, 1, 3, 5, 5, 6]):
    print(item, end=' ')

输出将是:1 3 5 6

要返回一个列表对象,你可以这样做:

>>> print(list(uniq([1, 1, 3, 5, 5, 6])))
[1, 3, 5, 6]

其他回答

有许多其他的答案提出了不同的方法,但它们都是批处理操作,其中一些会抛弃原始的顺序。这可能是可以的,这取决于你需要什么,但如果你想在每个值的第一个实例的顺序上迭代值,并且你想要立即删除重复的值而不是一次性删除,你可以使用这个生成器:

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

如果你想要一个列表,你可以这样做:

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]

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

下面的例子应该涵盖你要做的任何事情:

>>> t = [1, 2, 3, 1, 2, 3, 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]

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

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

请注意,这可能会有一些开销,首先创建一个字典,然后从它创建一个列表。如果您实际上不需要保留顺序,那么使用集合通常会更好,特别是因为它提供了更多的操作。查看这个问题,了解更多细节和在删除重复项时保留顺序的替代方法。


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

您可以比较集合和列表的长度,并将集合项保存到列表。

if len(t) != len(set(t)):
    t = [x for x in set(t)]
     

一个更好的方法是,

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]

秩序得以维持。

在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中,常规字典变得既有序又紧凑。(此特性适用于CPython和PyPy,但在其他实现中可能不存在)。这为我们提供了一种新的最快的方法,在保持秩序的同时减少数据:

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

在Python 3.7中,常规字典保证在所有实现中都是有序的。所以,最短最快的解决方案是:

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