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


当前回答

有时你需要删除重复的项目,而不需要创建新的列表。例如,列表很大,或者将其作为影子副本保存

from collections import Counter
cntDict = Counter(t)
for item,cnt in cntDict.items():
    for _ in range(cnt-1):
        t.remove(item)

其他回答

另一种解决方案可能如下。以item为键,index为值,从列表中创建一个字典,然后打印字典键。

>>> lst = [1, 3, 4, 2, 1, 21, 1, 32, 21, 1, 6, 5, 7, 8, 2]
>>>
>>> dict_enum = {item:index for index, item in enumerate(lst)}
>>> print dict_enum.keys()
[32, 1, 2, 3, 4, 5, 6, 7, 8, 21]

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

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

它需要安装一个第三方模块,但包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的作者。

这个人关心的是没有太多麻烦的订单(OrderdDict & others)。可能不是最python化的方式,也不是最短的方式,但却达到了目的:

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

今天,一位同事将接受的答案作为他的代码的一部分发给了我进行代码审阅。 虽然我很欣赏这个问题答案的优雅,但我对他的表现并不满意。 我尝试过这个解决方案(我使用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