如何从列表中删除重复项,同时保持顺序?使用集合删除重复项会破坏原始顺序。 是否有内置的或python的习语?


当前回答

sequence = ['1', '2', '3', '3', '6', '4', '5', '6']
unique = []
[unique.append(item) for item in sequence if item not in unique]

unique→[1、(2)、(3)、(6)、(4)、(5)]

其他回答

对于另一个非常古老的问题的一个非常晚的回答:

itertools食谱有一个函数可以做到这一点,使用了见集技术,但是:

处理标准键函数。 不使用不体面的黑客。 通过预绑定优化循环。加,而不是查N次。(f7也这样做,但有些版本没有。) 通过使用ifilterfalse优化循环,因此只需遍历Python中唯一的元素,而不是所有元素。(当然,您仍然在ifilterfalse中遍历所有它们,但这是在C中,而且要快得多。)

Is it actually faster than f7? It depends on your data, so you'll have to test it and see. If you want a list in the end, f7 uses a listcomp, and there's no way to do that here. (You can directly append instead of yielding, or you can feed the generator into the list function, but neither one can be as fast as the LIST_APPEND inside a listcomp.) At any rate, usually, squeezing out a few microseconds is not going to be as important as having an easily-understandable, reusable, already-written function that doesn't require DSU when you want to decorate.

和所有的食谱一样,它也有更多的版本。

如果你只想要无键的情况,你可以简化为:

def unique(iterable):
    seen = set()
    seen_add = seen.add
    for element in itertools.ifilterfalse(seen.__contains__, iterable):
        seen_add(element)
        yield element

我不是在找死马(这个问题已经很老了,已经有很多好的答案了),但是这里有一个使用熊猫的解决方案,在很多情况下都非常快,而且使用起来非常简单。

import pandas as pd

my_list = [0, 1, 2, 3, 4, 1, 2, 3, 5]

>>> pd.Series(my_list).drop_duplicates().tolist()
# Output:
# [0, 1, 2, 3, 4, 5]

5倍更快减少变种,但更复杂

>>> l = [5, 6, 6, 1, 1, 2, 2, 3, 4]
>>> 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())
# use 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]
[5, 6, 1, 2, 3, 4]

在CPython 3.6+(以及从Python 3.7+开始的所有其他Python实现)中,字典是有序的,因此从可迭代对象中删除重复项同时保持其原始顺序的方法是:

>>> list(dict.fromkeys('abracadabra'))
['a', 'b', 'r', 'c', 'd']

在Python 3.5及以下版本(包括Python 2.7)中,使用OrderedDict。我的计时表明,这是Python 3.5的各种方法中最快和最短的(当它获得C实现时;在3.5之前,它仍然是最清晰的解决方案,尽管不是最快的)。

>>> from collections import OrderedDict
>>> list(OrderedDict.fromkeys('abracadabra'))
['a', 'b', 'r', 'c', 'd']

如果你经常使用pandas,并且美学优先于性能,那么考虑内置函数pandas. series .drop_duplicate:

    import pandas as pd
    import numpy as np

    uniquifier = lambda alist: pd.Series(alist).drop_duplicates().tolist()

    # from the chosen answer 
    def f7(seq):
        seen = set()
        seen_add = seen.add
        return [ x for x in seq if not (x in seen or seen_add(x))]

    alist = np.random.randint(low=0, high=1000, size=10000).tolist()

    print uniquifier(alist) == f7(alist)  # True

时间:

    In [104]: %timeit f7(alist)
    1000 loops, best of 3: 1.3 ms per loop
    In [110]: %timeit uniquifier(alist)
    100 loops, best of 3: 4.39 ms per loop