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


当前回答

获得唯一项目集合的常用方法是使用集合。集合是不同对象的无序集合。要从任何可迭代对象创建一个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解决方案都要求项是可哈希的。这通常意味着它们必须是不可变的。如果你必须处理不可哈希的项(例如列表对象),那么你将不得不使用一种缓慢的方法,你基本上必须在一个嵌套循环中比较每个项。

其他回答

从列表中删除重复项的最佳方法是使用set()函数,该函数在python中可用,再次将该集合转换为列表

In [2]: some_list = ['a','a','v','v','v','c','c','d']
In [3]: list(set(some_list))
Out[3]: ['a', 'c', 'd', 'v']
def remove_duplicates(A):
   [A.pop(count) for count,elem in enumerate(A) if A.count(elem)!=1]
   return A

用于删除重复项的列表推导

简单易行:

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]

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]

到目前为止,我看到的所有保持顺序的方法要么使用朴素比较(时间复杂度最多为O(n^2)),要么使用限制于可哈希输入的重载OrderedDicts/set+list组合。下面是一个与哈希无关的O(nlogn)解决方案:

更新增加了关键参数、文档和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]]))]