我想从下面的列表中获得唯一的值:

['nowplaying', 'PBS', 'PBS', 'nowplaying', 'job', 'debate', 'thenandnow']

我需要的输出是:

['nowplaying', 'PBS', 'job', 'debate', 'thenandnow']

这段代码工作:

output = []
for x in trends:
    if x not in output:
        output.append(x)
print(output)

有更好的解决方案吗?


当前回答

使用以下函数:

def uniquefy_list(input_list):
"""
This function  takes a list as input and return a list containing only unique elements from the input list

"""
output_list=[]
for elm123 in input_list:
    in_both_lists=0
    for elm234 in output_list:
        if elm123 == elm234:
            in_both_lists=1
            break
    if in_both_lists == 0:
        output_list.append(elm123)

return output_list

其他回答

如果我们需要保持元素的顺序,那么这样怎么样:

used = set()
mylist = [u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow']
unique = [x for x in mylist if x not in used and (used.add(x) or True)]

还有一个使用reduce的解决方案,没有临时使用的var。

mylist = [u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow']
unique = reduce(lambda l, x: l.append(x) or l if x not in l else l, mylist, [])

更新- 2020年12月-也许是最好的方法!

从python 3.7开始,标准字典保持插入顺序。

在3.7版更改:字典顺序保证为插入顺序。此行为是CPython 3.6版本的实现细节。

因此,这使我们能够使用dict.from_keys进行重复删除!

注意:感谢@rlat在评论中给我们这个方法!

mylist = [u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow']
unique = list(dict.fromkeys(mylist))

在速度方面——对我来说,它足够快,足够易读,成为我最喜欢的新方法!

更新- 2019年3月

第三个解,很简洁,但有点慢,因为。index是O(n)

mylist = [u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow']
unique = [x for i, x in enumerate(mylist) if i == mylist.index(x)]

更新- 2016年10月

另一种使用reduce的解决方案,但这次没有.append,这使得它更易于阅读和理解。

mylist = [u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow']
unique = reduce(lambda l, x: l+[x] if x not in l else l, mylist, [])
#which can also be writed as:
unique = reduce(lambda l, x: l if x in l else l+[x], mylist, [])

注意:请记住,我们获得的人类可读性越高,脚本的性能就越差。除了dict.from_keys方法,它是python 3.7+特有的。

import timeit

setup = "mylist = [u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow']"

#10x to Michael for pointing out that we can get faster with set()
timeit.timeit('[x for x in mylist if x not in used and (used.add(x) or True)]', setup='used = set();'+setup)
0.2029558869980974

timeit.timeit('[x for x in mylist if x not in used and (used.append(x) or True)]', setup='used = [];'+setup)
0.28999493700030143

# 10x to rlat for suggesting this approach!   
timeit.timeit('list(dict.fromkeys(mylist))', setup=setup)
0.31227896199925453

timeit.timeit('reduce(lambda l, x: l.append(x) or l if x not in l else l, mylist, [])', setup='from functools import reduce;'+setup)
0.7149233570016804

timeit.timeit('reduce(lambda l, x: l+[x] if x not in l else l, mylist, [])', setup='from functools import reduce;'+setup)
0.7379565160008497

timeit.timeit('reduce(lambda l, x: l if x in l else l+[x], mylist, [])', setup='from functools import reduce;'+setup)
0.7400134069976048

timeit.timeit('[x for i, x in enumerate(mylist) if i == mylist.index(x)]', setup=setup)
0.9154880290006986

回复评论

因为@莫妮卡问了一个关于“这是怎么工作的?”的好问题。献给每一个有问题的人。我将尝试更深入地解释这是如何工作的,以及这里发生了什么巫术;)

所以她首先问:

我试图理解为什么unique = [used.append(x) for x in mylist if x not in used]是不工作的。

它确实起作用了

>>> used = []
>>> mylist = [u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow']
>>> unique = [used.append(x) for x in mylist if x not in used]
>>> print used
[u'nowplaying', u'PBS', u'job', u'debate', u'thenandnow']
>>> print unique
[None, None, None, None, None]

问题是我们只是在唯一的变量中没有得到想要的结果,而只是在使用的变量中。这是因为在列表理解过程中.append会修改所使用的变量并返回None。

因此,为了将结果放入唯一变量中,并且如果x未被使用,则仍然使用与.append(x)相同的逻辑,我们需要将这个.append调用移动到列表推导式的右侧,并在左侧返回x。

但如果我们太天真了,就这样:

>>> unique = [x for x in mylist if x not in used and used.append(x)]
>>> print unique
[]

我们将得不到任何回报。

同样,这是因为.append方法返回None,它会在我们的逻辑表达式上显示如下外观:

x not in used and None

这基本上总是:

当使用x时,结果为False, 当x未被使用时,计算结果为None。

在这两种情况下(False/None),这将被视为假值,我们将得到一个空列表作为结果。

但是当x不被使用时,为什么这个值为None呢?有人可能会问。

这是因为Python的短路操作符就是这样工作的。

表达式x和y首先求x的值;如果x为false,则其值为 返回;否则,计算y,结果值为 返回。

因此,当x未被使用时(即当它为True时),下一部分或表达式将被计算(using .append(x)),并返回它的值(None)。

但这就是我们想要的,为了从具有重复项的列表中获得唯一的元素,我们希望仅当它们第一次遇到时才将它们追加到新列表中。

因此,我们希望只在x未被使用时才对used。append(x)求值,如果有办法将None值转换为真值就可以了,对吧?

是的,这就是第二种短路操作者发挥作用的地方。

表达式x或y首先求x的值;如果x为真,它的值为 返回;否则,计算y,结果值为 返回。

我们知道.append(x)总是假的,所以如果我们只是在它旁边加上一个或,我们总是会得到下一个部分。这就是为什么我们写:

x not in used and (used.append(x) or True)

因此,我们可以求use .append(x)的值并得到True结果,只有当表达式的第一部分(x未被使用)为True时。

类似的方式可以在第二种方法中看到reduce方法。

(l.append(x) or l) if x not in l else l
#similar as the above, but maybe more readable
#we return l unchanged when x is in l
#we append x to l and return l when x is not in l
l if x in l else (l.append(x) or l)

我们去的地方:

将x追加到l并在x不在l时返回l。由于or语句,. Append被求值并在此之后返回l。 当x在l中时,返回l原封不动

为了与我使用的类型保持一致:

mylist = list(set(mylist))

如果你在你的代码中使用numpy(对于大量的数据来说,这可能是一个很好的选择),检查numpy.unique:

>>> import numpy as np
>>> wordsList = [u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow']
>>> np.unique(wordsList)
array([u'PBS', u'debate', u'job', u'nowplaying', u'thenandnow'], 
      dtype='<U10')

(http://docs.scipy.org/doc/numpy/reference/generated/numpy.unique.html)

可以看到,numpy不仅支持数值数据,还支持字符串数组。当然,结果是一个numpy数组,但这并不重要,因为它仍然表现得像一个序列:

>>> for word in np.unique(wordsList):
...     print word
... 
PBS
debate
job
nowplaying
thenandnow

如果你真的想要返回一个普通的python列表,你总是可以调用list()。

但是,结果是自动排序的,从上面的代码片段可以看出。如果需要保留列表顺序,则签出numpy unique而不进行排序。

维持秩序:

# oneliners
# slow -> . --- 14.417 seconds ---
[x for i, x in enumerate(array) if x not in array[0:i]]

# fast -> . --- 0.0378 seconds ---
[x for i, x in enumerate(array) if array.index(x) == i]

# multiple lines
# fastest -> --- 0.012 seconds ---
uniq = []
[uniq.append(x) for x in array if x not in uniq]
uniq

顺序不重要:

# fastest-est -> --- 0.0035 seconds ---
list(set(array))

Python列表:

>>> a = ['a', 'b', 'c', 'd', 'b']

要获得唯一的项,只需将其转换为一个集合(如果需要,您可以将其转换回列表):

>>> b = set(a)
>>> print(b)
{'b', 'c', 'd', 'a'}