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


当前回答

从列表中删除重复项的最佳方法是使用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']

其他回答

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

可以使用Python set或dict.fromkeys()方法删除重复项。 dict.fromkeys()方法将一个列表转换为一个字典。字典不能包含重复的值,因此dict.fromkeys()将返回只有唯一值的字典。 集,像字典一样,不能包含重复的值。如果将列表转换为集合,则删除所有重复项。

方法一:幼稚法

mylist = [5, 10, 15, 20, 3, 15, 25, 20, 30, 10, 100]

uniques = []

for i in mylist:

    if i not in uniques:

       uniques.append(i)

print(uniques)

方法二:使用set()

mylist = [5, 10, 15, 20, 3, 15, 25, 20, 30, 10, 100]

myset = set(mylist)

print(list(myset))

减少变量与顺序保存:

假设我们有一个列表:

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]

创建一个新的列表,保持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]

这将在添加之前检查之前没有出现在列表中的每个新元素。 它也不需要进口。

它需要安装一个第三方模块,但包iteration_utilities包含一个unique_everseen1函数,可以删除所有重复的同时保留顺序:

>>> from iteration_utilities import unique_everseen

>>> list(unique_everseen(['a', 'b', 'c', 'd'] + ['a', 'c', 'd']))
['a', 'b', 'c', 'd']

如果你想避免列表添加操作的开销,你可以使用itertools。链:

>>> from itertools import chain
>>> list(unique_everseen(chain(['a', 'b', 'c', 'd'], ['a', 'c', 'd'])))
['a', 'b', 'c', 'd']

unique_everseen也适用于列表中有不可哈希项(例如列表)的情况:

>>> from iteration_utilities import unique_everseen
>>> list(unique_everseen([['a'], ['b'], 'c', 'd'] + ['a', 'c', 'd']))
[['a'], ['b'], 'c', 'd', 'a']

然而,这将比项目是可哈希的(多)慢。


1披露:我是iteration_utilities-library的作者。