如何从列表中删除重复项,同时保留顺序?使用集合来删除重复项会破坏原始顺序。是否有内置函数或Python惯用语?
如何从列表中删除重复项,同时保留顺序?使用集合来删除重复项会破坏原始顺序。是否有内置函数或Python惯用语?
MizardX的回答提供了多种方法的好集合。
这是我在大声思考时想出来的:
mylist = [x for i,x in enumerate(mylist) if x not in mylist[i+1:]]
这将保持顺序并在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]
l = [1,2,2,3,3,...]
n = []
n.extend(ele for ele in l if ele not in set(n))
一个生成器表达式,使用集合的O(1)查找来确定是否将元素包含在新列表中。
extend
和基于被扩展的对象的生成器表达式(因此+1),但是set(n)
在每个阶段都会重新计算(这是线性的),这将使整体方法变为二次。实际上,这几乎肯定比仅使用ele in n
更糟糕。为了进行单个成员资格测试而创建一个集合不值得花费集合创建的代价。尽管如此-这是一种有趣的方法。 - John Coleman使用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])
你可以做一个有点丑陋的列表推导式黑客。
[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]
。 - Evpokdef 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]]
values_non_duplicated = [value for index, value in enumerate(values) if value not in values[ : index]]
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()
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']
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
O(n)
操作,并且您要对每个项执行该操作,因此您的解决方案的复杂度将为O(n^2)
。这对于如此微不足道的问题来说是无法接受的。 - Nikita Volkov