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


当前回答

我没有看到非哈希值的答案,一行,nlog n,标准库,所以这是我的答案:

list(map(operator.itemgetter(0), itertools.groupby(sorted(items))))

或作为一个生成函数:

def unique(items: Iterable[T]) -> Iterable[T]:
    """For unhashable items (can't use set to unique) with a partial order"""
    yield from map(operator.itemgetter(0), itertools.groupby(sorted(items)))

其他回答

这里有很多答案使用set(..)(考虑到元素是可哈希的,这是快速的)或list(它的缺点是它会导致O(n2)算法。

我建议的函数是一个混合的函数:我们使用set(..)来表示可哈希的项,使用list(..)来表示不可哈希的项。此外,它被实现为一个生成器,例如,我们可以限制项目的数量,或做一些额外的过滤。

最后,我们还可以使用一个key参数来指定元素应以何种方式惟一。例如,如果我们想过滤一个字符串列表,这样输出中的每个字符串都有不同的长度,我们可以使用这个。

def uniq(iterable, key=lambda x: x):
    seens = set()
    seenl = []
    for item in iterable:
        k = key(item)
        try:
            seen = k in seens
        except TypeError:
            seen = k in seenl
        if not seen:
            yield item
            try:
                seens.add(k)
            except TypeError:
                seenl.append(k)

我们现在可以这样使用:

>>> list(uniq(["apple", "pear", "banana", "lemon"], len))
['apple', 'pear', 'banana']
>>> list(uniq(["apple", "pear", "lemon", "banana"], len))
['apple', 'pear', 'banana']
>>> list(uniq(["apple", "pear", {}, "lemon", [], "banana"], len))
['apple', 'pear', {}, 'banana']
>>> list(uniq(["apple", "pear", {}, "lemon", [], "banana"]))
['apple', 'pear', {}, 'lemon', [], 'banana']
>>> list(uniq(["apple", "pear", {}, "lemon", {}, "banana"]))
['apple', 'pear', {}, 'lemon', 'banana']

因此,它是一个唯一性过滤器,可以在任何可迭代对象上工作并过滤出唯一性对象,而不管这些唯一性对象是否可哈希。

它做了一个假设:如果一个对象是可哈希的,而另一个对象不是,这两个对象永远不相等。严格地说,这是可能发生的,尽管它是非常罕见的。

尝试使用集合:

import sets
t = sets.Set(['a', 'b', 'c', 'd'])
t1 = sets.Set(['a', 'b', 'c'])

print t | t1
print t - t1

简单易行:

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]

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

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

在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']