在python中,从列表中删除重复项的最快算法是什么,以便所有元素都是唯一的*,同时保持顺序*?

在python中,从列表中删除重复项的最快算法是什么,以便所有元素都是唯一的*,同时保持顺序*?

In Python, what is the fastest algorithm for removing duplicates from a list so that all elements are unique *while preserving order*?

本问题已经有最佳答案,请猛点这里访问。

例如:

1
2
3
>>> x = [1, 1, 2, 'a', 'a', 3]
>>> unique(x)
[1, 2, 'a', 3]

假设列表元素是可哈希的。

澄清:结果应保留清单中的第一份副本。例如,[1,2,3,2,3,1]变为[1,2,3]。


1
2
3
4
5
6
7
8
9
10
11
12
def unique(items):
    found = set([])
    keep = []

    for item in items:
        if item not in found:
            found.add(item)
            keep.append(item)

    return keep

print unique([1, 1, 2, 'a', 'a', 3])

使用:

1
lst = [8, 8, 9, 9, 7, 15, 15, 2, 20, 13, 2, 24, 6, 11, 7, 12, 4, 10, 18, 13, 23, 11, 3, 11, 12, 10, 4, 5, 4, 22, 6, 3, 19, 14, 21, 11, 1, 5, 14, 8, 0, 1, 16, 5, 10, 13, 17, 1, 16, 17, 12, 6, 10, 0, 3, 9, 9, 3, 7, 7, 6, 6, 7, 5, 14, 18, 12, 19, 2, 8, 9, 0, 8, 4, 5]

使用Timeit模块:

1
$ python -m timeit -s 'import uniquetest' 'uniquetest.etchasketch(uniquetest.lst)'

对于各种其他功能(我以它们的海报命名),我有以下结果(在我的第一代Intel MacBook Pro上):

1
2
3
4
5
6
7
8
9
Allen:                  14.6 μs per loop [1]
Terhorst:               26.6 μs per loop
Tarle:                  44.7 μs per loop
ctcherry:               44.8 μs per loop
Etchasketch 1 (short):  64.6 μs per loop
Schinckel:              65.0 μs per loop
Etchasketch 2:          71.6 μs per loop
Little:                 89.4 μs per loop
Tyler:                 179.0 μs per loop

[1]请注意,Allen在适当的位置修改了列表-我认为这已经扭曲了时间,因为timeit模块运行代码100000次,其中99999次使用无重复列表。

总结:用集合直接实现胜过混淆一行程序:—)


这里的解决方案fastest太远了(*以下输入:) P / < >

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def del_dups(seq):
    seen = {}
    pos = 0
    for item in seq:
        if item not in seen:
            seen[item] = True
            seq[pos] = item
            pos += 1
    del seq[pos:]

lst = [8, 8, 9, 9, 7, 15, 15, 2, 20, 13, 2, 24, 6, 11, 7, 12, 4, 10, 18,
       13, 23, 11, 3, 11, 12, 10, 4, 5, 4, 22, 6, 3, 19, 14, 21, 11, 1,
       5, 14, 8, 0, 1, 16, 5, 10, 13, 17, 1, 16, 17, 12, 6, 10, 0, 3, 9,
       9, 3, 7, 7, 6, 6, 7, 5, 14, 18, 12, 19, 2, 8, 9, 0, 8, 4, 5]
del_dups(lst)
print(lst)
# -> [8, 9, 7, 15, 2, 20, 13, 24, 6, 11, 12, 4, 10, 18, 23, 3, 5, 22, 19, 14,
#     21, 1, 0, 16, 17]

词典lookup也更快slightly那么"设置"一个在Python 3。 P / < >


最快的速度取决于你的列表中有多少是重复的。如果几乎是所有重复项,只有很少的唯一项,那么创建新列表可能会更快。如果它主要是唯一的项目,从原始列表(或副本)中删除它们将更快。

下面是一个用于就地修改列表的列表:

1
2
3
4
5
6
7
8
def unique(items):
  seen = set()
  for i in xrange(len(items)-1, -1, -1):
    it = items[i]
    if it in seen:
      del items[i]
    else:
      seen.add(it)

向后迭代索引可以确保移除项不会影响迭代。


这是我找到的最快的就地方法(假设有大量重复):

1
2
3
4
5
def unique(l):
    s = set(); n = 0
    for x in l:
        if x not in s: s.add(x); l[n] = x; n += 1
    del l[n:]

这比Allen的实现快10%,它是基于这个实现的(用timeit.repeat计时,由psyco编译的jit)。它保留任何副本的第一个实例。

雷普顿:如果你能确认我的时间,我会很感兴趣的。


这是可能的simplest方式: P / < >

1
list(OrderedDict.fromkeys(iterable))

20世纪的Python 3.5,ordereddict现在implemented在C,所以这会是现在的shortest,cleanest,和fastest。 P / < >


基于发电机的强制性变化:

1
2
3
4
5
6
def unique(seq):
  seen = set()
  for x in seq:
    if x not in seen:
      seen.add(x)
      yield x

一班轮:

1
new_list = reduce(lambda x,y: x+[y][:1-int(y in x)], my_list, [])

这就是一个fastest,comparing所有的东西从这lengthy discussion和其他的回答给了睾丸,refering给该基准。它的另一个25 %的速度比的fastest功能从discussion,f8。谢谢到戴维科比为理念。 P / < >

1
2
3
4
def uniquify(seq):
    seen = set()
    seen_add = seen.add
    return [x for x in seq if x not in seen and not seen_add(x)]

一定的时间比较: P / < >

1
2
3
4
5
6
$ python uniqifiers_benchmark.py
* f8_original 3.76
* uniquify 3.0
* terhorst 5.44
* terhorst_localref 4.08
* del_dups 4.76


在一个地方的一个liner为这样: P / < >

1
2
3
>>> x = [1, 1, 2, 'a', 'a', 3]
>>> [ item for pos,item in enumerate(x) if x.index(item)==pos ]
[1, 2, 'a', 3]

摘自http://www.peterbe.com/plog/uniqifiers-benchmark

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def f5(seq, idfun=None):  
    # order preserving
    if idfun is None:
        def idfun(x): return x
    seen = {}
    result = []
    for item in seq:
        marker = idfun(item)
        # in old Python versions:
        # if seen.has_key(marker)
        # but in new ones:
        if marker in seen: continue
        seen[marker] = 1
        result.append(item)
    return result

实际上,您可以在Python中做一些非常酷的事情来解决这个问题。您可以创建一个列表理解,在构建时引用它自己。如下:

1
2
3
   # remove duplicates...
   def unique(my_list):
       return [x for x in my_list if x not in locals()['_[1]'].__self__]

编辑:我删除了"self",它在mac os x,python 2.5.1上工作。

_[1]是python对新列表的"秘密"引用。当然,上面有点混乱,但是你可以根据需要调整它。例如,您实际上可以编写一个返回对理解的引用的函数;它看起来更像:

1
return [x for x in my_list if x not in this_list()]

remove duplicates和维护秩序。 P / < >

这是一个快速的2 liner,leverages建在functionality of comprehensions列表和dicts。 P / < >

1
2
3
4
5
6
7
x = [1, 1, 2, 'a', 'a', 3]

tmpUniq = {} # temp variable used below
results = [tmpUniq.setdefault(i,i) for i in x if i not in tmpUniq]

print results
[1, 2, 'a', 3]

"dict.setdefaults(功能)的价值returns号好号添加到高温dict直接在comprehension列表。用"建在功能和hashes之dict将工作要maximize效率为过程。 P / < >


是否必须首先将重复项放在列表中?在向上查找元素时没有开销,但是在添加元素时会有一些开销(尽管开销应该是O(1))。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
>>> x  = []
>>> y = set()
>>> def add_to_x(val):
...     if val not in y:
...             x.append(val)
...             y.add(val)
...     print x
...     print y
...
>>> add_to_x(1)
[1]
set([1])
>>> add_to_x(1)
[1]
set([1])
>>> add_to_x(1)
[1]
set([1])
>>>


在python中has_key是o(1)。哈希的插入和检索也是O(1)。两次循环N个项目,所以o(n)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def unique(list):
  s = {}
  output = []
  for x in list:
    count = 1
    if(s.has_key(x)):
      count = s[x] + 1

    s[x] = count
  for x in list:
    count = s[x]
    if(count > 0):
      s[x] = 0
      output.append(x)
  return output

o(n)如果dict是hash,o(nlogn)如果dict是tree,并且简单、固定。感谢马修的建议。抱歉,我不知道底层类型。

1
2
3
4
5
6
7
8
9
10
11
def unique(x):    
  output = []
  y = {}
  for item in x:
    y[item] =""

  for item in x:
    if item in y:
      output.append(item)

  return output

这里有一些伟大的,有效的解决方案。但是,对于不关心绝对最有效的O(n)解决方案的任何人,我将使用简单的单行O(n^2*log(n))解决方案:

1
2
def unique(xs):
    return sorted(set(xs), key=lambda x: xs.index(x))

或更有效的双内衬O(n*log(n))解决方案:

1
2
3
def unique(xs):
    positions = dict((e,pos) for pos,e in reversed(list(enumerate(xs))))
    return sorted(set(xs), key=lambda x: positions[x])

这里是两个recipes从itertools文件: P / < >

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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

def unique_justseen(iterable, key=None):
   "List unique elements, preserving order. Remember only the element just seen."
    # unique_justseen('AAAABBBCCDAABBB') --> A B C D A B
    # unique_justseen('ABBCcAD', str.lower) --> A B C A D
    return imap(next, imap(itemgetter(1), groupby(iterable, key)))

我对python没有经验,但是一种算法是对列表进行排序,然后删除重复项(通过与列表中以前的项进行比较),最后通过与旧列表进行比较在新列表中找到位置。

更长的答案:http://aspn.activestate.com/aspn/cookbook/python/recipe/52560


1
2
3
4
5
6
>>> def unique(list):
...   y = []
...   for x in list:
...     if x not in y:
...       y.append(x)
...   return y

如果从terhost的答案中的call to set()中去掉空列表,您会得到一点速度提升。

变化:发现=集([])到:SED= SET()

不过,你根本不需要这套。

1
2
3
4
5
6
7
8
def unique(items):
    keep = []

    for item in items:
        if item not in keep:
            keep.append(item)

    return keep

使用Timeit,我得到了以下结果:

带套件([])--4.97210427363带set()--4.65712377445不带套件--3.44865284975


1
2
3
4
5
6
7
8
9
10
x = [] # Your list  of items that includes Duplicates

# Assuming that your list contains items of only immutable data types

dict_x = {}

dict_x = {item : item for i, item in enumerate(x) if item not in dict_x.keys()}
# Average t.c. = O(n)* O(1) ; furthermore the dict comphrehension and generator like behaviour of enumerate adds a certain efficiency and pythonic feel to it.

x = dict_x.keys() # if you want your output in list format

1
2
3
4
>>> x=[1,1,2,'a','a',3]
>>> y = [ _x for _x in x if not _x in locals()['_[1]'] ]
>>> y
[1, 2, 'a', 3]

"locals()["[1]"]是正在创建的列表的"秘密名称"。


我不知道这是不是很快,但至少很简单。

简单地说,先把它转换成一个集合,然后再转换成一个列表

1
2
def unique(container):
  return list(set(container))


在1,2,3,4,5,7,7,8,8,9,9,3,45 = [ ] P / < >

独特的DEF(L): P / < >

1
2
3
4
5
ids={}
for item in l:
    if not ids.has_key(item):
        ids[item]=item
return  ids.keys()

打印的 P / < >

打印独特(的) P / < > ----------------------------

inserting元素将以θ(n) 如果retrieving元也exiting或不会把时间常数 所有的测试项目也将把θ(n) 所以我们可以看到,这种解决方案将把θ(n) 熊在所有的词典,在Python implemented by哈希表 P / < >


我没有做任何测试,但是一个可能的算法是创建第二个列表,并遍历第一个列表。如果项目不在第二个列表中,请将其添加到第二个列表中。

1
2
3
4
5
x = [1, 1, 2, 'a', 'a', 3]
y = []
for each in x:
    if each not in y:
        y.append(each)

一次传球。

1
2
3
4
5
6
7
8
9
10
11
12
13
a = [1,1,'a','b','c','c']

new_list = []
prev = None

while 1:
    try:
        i = a.pop(0)
        if i != prev:
            new_list.append(i)
        prev = i
    except IndexError:
        break

推荐阅读

    linux命令删除用户组?

    linux命令删除用户组?,管理,密码,系统,用户组,用户,概念,命令,文件,管理员,

    linux删除重复项命令?

    linux删除重复项命令?,数据,系统,工具,电脑,项目,公式,百度,代码,名字,基础,

    linux硬链接删除命令?

    linux硬链接删除命令?,数据,系统,不了,时间,名称,链接,文件,档案,地方,设备,l

    linux交互删除命令?

    linux交互删除命令?,名称,不了,系统,文件夹,命令,通用,文件,目录,指令,方法,l

    linux删除无用的命令?

    linux删除无用的命令?,系统,软件,数据,员工,命令,信息,宽松,对比,状态,公司,L

    linux命令行删除网卡?

    linux命令行删除网卡?,地址,网络,系统,工具,信息,设备,名字,管理,服务,网卡,l

    linux命令删除字符串?

    linux命令删除字符串?,软件,系统,代码,名称,通用,连续,字符,字符串,命令,空

    linux删除整个命令?

    linux删除整个命令?,命令,文件夹,不了,名称,通用,系统,数据,文件,目录,格式,l

    linux如何命令删除?

    linux如何命令删除?,档案,系统,命令,文件,目录,通用,文件夹,终端,选项,参数,l

    删除路由命令linux?

    删除路由命令linux?,系统,信息,网络,地址,管理,环境,路由,命令,工作,基础,WIN

    linux命令删除当前行?

    linux命令删除当前行?,系统,位置,命令,文件夹,文件,标的,数据,环境,通用,不

    linux命令合并重复行?

    linux命令合并重复行?,地址,文件,系统,命令,代码,工作,基础,内容,两个,控制

    linux删除jog命令?

    linux删除jog命令?,工具,软件,连续,机器人,位置,中心,工作,平稳,人员,自动化

    linux删除服务的命令?

    linux删除服务的命令?,服务,系统,软件,平台,名称,管理,环境,产品,命令,文件,

    linux删除rm命令?

    linux删除rm命令?,系统,命令,文件夹,不了,通用,名称,环境,文件,目录,下面,lin

    linux系统删除的命令?

    linux系统删除的命令?,软件,系统,名称,工具,不了,命令,文件夹,电脑,通用,信

    linux删除命令文件夹?

    linux删除命令文件夹?,系统,数据,通用,文件夹,命令,文件,环境,百度,不了,名

    linux删除本行命令?

    linux删除本行命令?,系统,本行,档案,命令,资料,商业,文件,终端,目录,文件名,L

    linux删除第一行命令?

    linux删除第一行命令?,单位,系统,命令,标的,不了,数字,连续,名称,档案,文件,m

    linux删除本行命令?

    linux删除本行命令?,系统,本行,档案,命令,资料,商业,文件,终端,目录,文件名,L