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

['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)

有更好的解决方案吗?


当前回答

我知道这是一个老问题,但我有一个独特的解决方案:类继承!:

class UniqueList(list):
    def appendunique(self,item):
        if item not in self:
            self.append(item)
            return True
        return False

然后,如果你想唯一地将项目附加到列表中,你只需在UniqueList上调用appendunique。因为它继承自一个列表,所以它基本上就像一个列表,所以你可以使用index()等函数。因为它返回true或false,所以可以知道追加是成功(唯一项)还是失败(已经在列表中)。

要从列表中获得唯一的项列表,请使用for循环将项追加到UniqueList(然后复制到列表中)。

示例用法代码:

unique = UniqueList()

for each in [1,2,2,3,3,4]:
    if unique.appendunique(each):
        print 'Uniquely appended ' + str(each)
    else:
        print 'Already contains ' + str(each)

打印:

Uniquely appended 1
Uniquely appended 2
Already contains 2
Uniquely appended 3
Already contains 3
Uniquely appended 4

复制到列表:

unique = UniqueList()

for each in [1,2,2,3,3,4]:
    unique.appendunique(each)

newlist = unique[:]
print newlist

打印:

[1, 2, 3, 4]

其他回答

首先,你给出的例子不是一个有效的列表。

example_list = [u'nowplaying',u'PBS', u'PBS', u'nowplaying', u'job', u'debate',u'thenandnow']

假设以上是示例列表。然后,您可以使用下面的配方来给出itertools示例文档,该文档可以返回唯一的值,并按照您的要求保留顺序。这里的可迭代对象是example_list

from itertools import ifilterfalse

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

Set是一个无序且唯一元素的集合。所以,你可以使用set来获得一个唯一的列表:

unique_list = list(set([u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow']))

删除重复项的选项可能包括以下通用数据结构:

集合:无序的,唯一的元素 有序集:有序的、唯一的元素

下面是关于如何在Python中快速获取其中一个的总结。

鉴于

from collections import OrderedDict


seq = [u"nowplaying", u"PBS", u"PBS", u"nowplaying", u"job", u"debate", u"thenandnow"]

Code

选项1 -一组(无序):

list(set(seq))
# ['thenandnow', 'PBS', 'debate', 'job', 'nowplaying']
    

Python没有有序集,但这里有一些模拟有序集的方法。

选项2 -一个OrderedDict(插入顺序):

list(OrderedDict.fromkeys(seq))
# ['nowplaying', 'PBS', 'job', 'debate', 'thenandnow']

选项3 -字典(插入顺序),Python 3.6+中的默认值。在这篇文章中可以看到更多细节:

list(dict.fromkeys(seq))
# ['nowplaying', 'PBS', 'job', 'debate', 'thenandnow']

注意:列出的元素必须是可哈希的。在这篇博客文章中查看后一个示例的详细信息。此外,请参阅R. Hettinger关于相同技术的帖子;保序字典是从他早期的一个实现扩展而来的。参见更多关于总排序的信息。

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

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原封不动

def get_distinct(original_list):
    distinct_list = []
    for each in original_list:
        if each not in distinct_list:
            distinct_list.append(each)
    return distinct_list