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


当前回答

你可以使用set来删除重复项:

mylist = list(set(mylist))

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

mylist.sort()

其他回答

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

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

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

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

在这个答案中,将有两个部分:两个唯一的解,和一个特定解的速度图。

删除重复项

这些答案大多只删除可哈希的重复项,但这个问题并不意味着它不需要可哈希项,这意味着我将提供一些不需要可哈希项的解决方案。

集合。Counter是标准库中的一个功能强大的工具,可以完美地实现这一点。只有另一种解决方案里面有Counter。然而,该解决方案也仅限于可哈希键。

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

我也得到了两个解。另一个解决方案是保持条目的顺序,使用OrderedDict和Counter的子类,命名为'OrderedCounter'。下面是函数:

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适用于任何删除重复项的方法,它不一定要保持顺序。它不需要为不可hashables工作,但它可以。

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

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

y轴是花费的秒数。

x轴是函数作用的数字。

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

对于有序的不可哈希对象:[[list(range(y)) + list(range(y)) For y in range(x)] For x in range(0,1000,10)]

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

还要注意,图例上的键是我试图猜测的函数实现中最重要的部分。至于哪个功能是最好的还是最差的呢?图表说明了一切。

解决了这个问题,下面是图表。

无序Hashables

(放大)

命令Hashables

(放大)

命令Unhashables

(放大)

为了完整起见,由于这是一个非常流行的问题,toolz库提供了一个独特的函数:

>>> tuple(unique((1, 2, 3)))
(1, 2, 3)
>>> tuple(unique((1, 2, 1, 3)))
(1, 2, 3)

Python内置了许多函数,您可以使用set()来删除列表中的重复项。 根据你的例子,下面有两个列表t和t2

t = ['a', 'b', 'c', 'd']
t2 = ['a', 'c', 'd']
result = list(set(t) - set(t2))
result

答:[b]