我有一个列表,我正在尝试从中删除重复的项目。我正在使用python 2.7.1,所以我可以简单地使用 set()函数。但是,这会重新排序我的列表。对于我的具体情况,这是不可接受的。
下面是我写的一个函数;这样做。但是我想知道是否有更好/更快的方式。对此也有任何意见,将不胜感激。
def ordered_set(list_):
newlist = []
lastitem = None
for item in list_:
if item != lastitem:
newlist.append(item)
lastitem = item
return newlist
上述功能假设所有项目都不是无,并且项目是有序的(即 ['a','a','a',' b','b','c','d'] )
上述函数返回 ['a','a','a','b','b','c','d'] 为 ['a ','b','c','d'] 。
答案 0 :(得分:12)
使用set的另一种非常快速的方法:
def remove_duplicates(lst):
dset = set()
# relies on the fact that dset.add() always returns None.
return [item for item in lst
if item not in dset and not dset.add(item)]
答案 1 :(得分:8)
使用OrderedDict:
from collections import OrderedDict
l = ['a', 'a', 'a', 'b', 'b', 'c', 'd']
d = OrderedDict()
for x in l:
d[x] = True
# prints a b c d
for x in d:
print x,
print
答案 2 :(得分:7)
假设输入序列是无序的,这里是O(N)
解决方案(空间和时间)。
它会生成一个删除了重复项的序列,同时保留与输入序列中出现的相同顺序的唯一项。
>>> def remove_dups_stable(s):
... seen = set()
... for i in s:
... if i not in seen:
... yield i
... seen.add(i)
>>> list(remove_dups_stable(['q', 'w', 'e', 'r', 'q', 'w', 'y', 'u', 'i', 't', 'e', 'p', 't', 'y', 'e']))
['q', 'w', 'e', 'r', 'y', 'u', 'i', 't', 'p']
答案 3 :(得分:5)
我知道这已经得到了解答,但这里有一个单行(加上导入):
from collections import OrderedDict
def dedupe(_list):
return OrderedDict((item,None) for item in _list).keys()
>>> dedupe(['q', 'w', 'e', 'r', 'q', 'w', 'y', 'u', 'i', 't', 'e', 'p', 't', 'y', 'e'])
['q', 'w', 'e', 'r', 'y', 'u', 'i', 't', 'p']
答案 4 :(得分:3)
我认为这完全没问题。你获得的O(n)表现是你所希望的最佳表现。
如果列表无序,那么您需要一个帮助器set
来包含您已经访问过的项目,但在您的情况下则没有必要。
答案 5 :(得分:2)
如果您的列表没有排序,那么您的问题没有意义。 例如[1,2,1]可以成为[1,2]或[2,1]
如果您的列表很大,您可能希望使用SLICE将结果写回同一列表以节省内存:
>>> x=['a', 'a', 'a', 'b', 'b', 'c', 'd']
>>> x[:]=[x[i] for i in range(len(x)) if i==0 or x[i]!=x[i-1]]
>>> x
['a', 'b', 'c', 'd']
有关内联删除的信息,请参阅Remove items from a list while iterating或Remove items from a list while iterating without using extra memory in Python
你可以使用的一个技巧是,如果你知道x被排序,你知道x [i] = x [i + j]那么你不需要检查x [i]和x [i +]之间的任何东西j](如果您不需要删除这些j值,您只需将所需的值复制到新列表中)
因此,如果集合中的所有内容都是唯一的,那么你就无法击败n次操作,即len(set(x))= len(x) 可能有一种算法将n比较作为最坏的情况,但可以将n / 2比较作为最佳情况(或者如果你知道某种方式事先知道len(x)/ len,那么它的最佳情况就是n / 2; set(x))> 2,因为您生成的数据):
最佳算法可能会使用二分搜索来找到分而治之类型方法中每个最小i的最大值j。初始除法可能是长度len(x)/近似(len(set(x)))。希望它可以执行,即使len(x)= len(set(x))它仍然只使用n次操作。
答案 6 :(得分:2)
中描述了unique_everseen解决方案 http://docs.python.org/2/library/itertools.html
def unique_everseen(iterable, key=None):
"List unique elements, preserving order. Remember all elements ever seen."
# unique_everseen('AAAABBBCCDAABBB') --> A B C D
# unique_everseen('ABBCcAD', str.lower) --> A B C D
seen = set()
seen_add = seen.add
if key is None:
for element in ifilterfalse(seen.__contains__, iterable):
seen_add(element)
yield element
else:
for element in iterable:
k = key(element)
if k not in seen:
seen_add(k)
yield element
答案 7 :(得分:0)
对我来说没问题。如果你真的想使用集合做这样的事情:
def ordered_set (_list) :
result = set()
lastitem = None
for item in _list :
if item != lastitem :
result.add(item)
lastitem = item
return sorted(tuple(result))
我不知道你会得到什么表现,你应该测试一下;可能是因为方法过热而一样!
如果你真的是偏执狂,就像我一样,请在这里阅读:
http://wiki.python.org/moin/HowTo/Sorting/
http://wiki.python.org/moin/PythonSpeed/PerformanceTips
记得这个(它包含答案):