如何在保留顺序的情况下从列表中删除重复项?

1033

如何从列表中删除重复项,同时保留顺序?使用集合来删除重复项会破坏原始顺序。是否有内置函数或Python惯用语?

31个回答

0

MizardX的回答提供了多种方法的好集合。

这是我在大声思考时想出来的:

mylist = [x for i,x in enumerate(mylist) if x not in mylist[i+1:]]

你的解决方案很好,但它只考虑了每个元素的最后一次出现。 如果要考虑每个元素的第一次出现,请使用以下代码: [x for i,x in enumerate(mylist) if x not in mylist[:i]] - Rivka
8
由于在列表中搜索是一项O(n)操作,并且您要对每个项执行该操作,因此您的解决方案的复杂度将为O(n^2)。这对于如此微不足道的问题来说是无法接受的。 - Nikita Volkov

0

这将保持顺序并在O(n)时间内运行。基本上的想法是在发现重复项时创建一个空洞并将其下沉到底部。利用读写指针。每当发现重复项时,只有读指针前进,写指针停留在重复条目上以覆盖它。

def deduplicate(l):
    count = {}
    (read,write) = (0,0)
    while read < len(l):
        if l[read] in count:
            read += 1
            continue
        count[l[read]] = True
        l[write] = l[read]
        read += 1
        write += 1
    return l[0:write]

0
l = [1,2,2,3,3,...]
n = []
n.extend(ele for ele in l if ele not in set(n))

一个生成器表达式,使用集合的O(1)查找来确定是否将元素包含在新列表中。


1
巧妙地使用extend和基于被扩展的对象的生成器表达式(因此+1),但是set(n)在每个阶段都会重新计算(这是线性的),这将使整体方法变为二次。实际上,这几乎肯定比仅使用ele in n更糟糕。为了进行单个成员资格测试而创建一个集合不值得花费集合创建的代价。尽管如此-这是一种有趣的方法。 - John Coleman

0

使用numpy数组中的_sorted_方法是一个相对有效的方法:

b = np.array([1,3,3, 8, 12, 12,12])    
numpy.hstack([b[0], [x[0] for x in zip(b[1:], b[:-1]) if x[0]!=x[1]]])

输出:

array([ 1,  3,  8, 12])

0

你可以做一个有点丑陋的列表推导式黑客。

[l[i] for i in range(len(l)) if l.index(l[i]) == i]

使用i,e in enumerate(l)代替for i in range(len(l)):l [i] - Evpok

0
一个简单的递归解决方案:
def uniquefy_list(a):
    return uniquefy_list(a[1:]) if a[0] in a[1:] else [a[0]]+uniquefy_list(a[1:]) if len(a)>1 else [a[0]]

0
一行代码的列表推导式:
values_non_duplicated = [value for index, value in enumerate(values) if value not in values[ : index]]

0
x = [1, 2, 1, 3, 1, 4]

# brute force method
arr = []
for i in x:
  if not i in arr:
    arr.insert(x[i],i)

# recursive method
tmp = []
def remove_duplicates(j=0):
    if j < len(x):
      if not x[j] in tmp:
        tmp.append(x[j])
      i = j+1  
      remove_duplicates(i)

      

remove_duplicates()

-1
一个不使用导入模块或集合的解决方案:
text = "ask not what your country can do for you ask what you can do for your country"
sentence = text.split(" ")
noduplicates = [(sentence[i]) for i in range (0,len(sentence)) if sentence[i] not in sentence[:i]]
print(noduplicates)

输出结果:

['ask', 'not', 'what', 'your', 'country', 'can', 'do', 'for', 'you']

这是O(N**2)复杂度加上每次进行列表切片。 - Jean-François Fabre

-1
如果您经常使用 pandas,并且更注重美观而非性能,则可以考虑使用内置函数 pandas.Series.drop_duplicates
    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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接