从Python中的列表中获取唯一值

我想从以下列表中获取唯一值:

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

我应该使用更好的解决方案吗?

2515758 次浏览

你的输出变量是什么类型?

Python是你需要的。像这样声明输出:

output = set()  # initialize an empty set

您已经准备好使用output.add(elem)添加元素并确保它们是唯一的。

警告:集合不保留列表的原始顺序。

首先正确声明您的列表,用逗号分隔。您可以通过将列表转换为集合来获取唯一值。

mylist = ['nowplaying', 'PBS', 'PBS', 'nowplaying', 'job', 'debate', 'thenandnow']myset = set(mylist)print(myset)

如果您进一步将其用作列表,您应该通过执行以下操作将其转换回列表:

mynewlist = list(myset)

另一种可能性,可能更快的方法是从头开始使用集合,而不是列表。那么你的代码应该是:

output = set()for x in trends:output.add(x)print(output)

正如已经指出的,集合不会保持原始顺序。如果您需要,您应该寻找有序集实现(更多信息请参阅这个问题)。

一个Python列表:

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

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

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

首先,您提供的示例不是有效列表。

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

假设上面是示例列表。然后你可以使用下面的配方作为给定的迭代工具示例文档,它可以返回唯一值并保留你似乎需要的顺序。这里的可迭代是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 Dseen = set()seen_add = seen.addif key is None:for element in ifilterfalse(seen.__contains__, iterable):seen_add(element)yield elementelse:for element in iterable:k = key(element)if k not in seen:seen_add(k)yield element
  1. 在代码的开头,只需将输出列表声明为空:output=[]
  2. 您可以使用此代码trends=list(set(trends))代替您的代码
def setlist(lst=[]):return list(set(lst))

试试这个函数,它类似于你的代码,但它是一个动态范围。

def unique(a):
k=0while k < len(a):if a[k] in a[k+1:]:a.pop(k)else:k=k+1


return a

要与我将使用的类型一致:

mylist = list(set(mylist))

使用以下功能:

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=0for elm234 in output_list:if elm123 == elm234:in_both_lists=1breakif in_both_lists == 0:output_list.append(elm123)
return output_list

set-唯一元素的无序集合。元素列表可以传递给set的构造函数。因此,传递带有重复元素的列表,我们得到带有唯一元素的集合,并将其转换回列表,然后得到带有唯一元素的列表。我不能说性能和内存开销,但我希望,它对小列表不是那么重要。

list(set(my_not_unique_list))

简单而简短。

相同顺序的唯一列表仅使用列表压缩。

> my_list = [1, 2, 1, 3, 2, 4, 3, 5, 4, 3, 2, 3, 1]> unique_list = [>    e>    for i, e in enumerate(my_list)>    if my_list.index(e) == i> ]> unique_list[1, 2, 3, 4, 5]

enumerates给出索引i和元素e作为tuple

my_list.index返回e的第一个索引。如果第一个索引不是i,则当前迭代的e不是列表中的第一个e

编辑

我应该注意的是,这不是一个很好的方法,在性能方面。这是只是一种仅使用列表压缩来实现它的方法。

对于长数组

s = np.empty(len(var))
s[:] = np.nan
for  x in  set(var):
x_positions = np.where(var==x)
s[x_positions[0][0]]=x

sorted_var=s[~np.isnan(s)]

如果您在代码中使用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...PBSdebatejobnowplayingthenandnow

如果你真的想要一个普通的python列表,你可以随时调用list()。

但是,结果会自动排序,正如您从上面的代码片段中看到的那样。如果需要保留列表顺序,请检查numpy唯一没有排序

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

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

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且没有临时used 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进行重复删除!

注意:在评论中给我们这种方法的学分是@陈志立

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]

问题是我们在unique变量中没有得到想要的结果,而只在used变量中得到。这是因为在列表理解期间.append修改了used变量并返回None

因此,为了将结果放入unique变量,并且仍然使用与.append(x) if x not in used相同的逻辑,我们需要将这个.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

这基本上总是:

  1. xused时计算为False
  2. x不在used中时,计算结果为None

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

但是,当x不在used时,为什么这会评估为None?有人可能会问。

这是因为这就是Python的短路运算符作品

表达式x and y首先计算x;如果x为false,则其值为返回;否则,y被计算,结果值为返回

因此,当x未被使用时(即当其#1)下一个部分或表达式将被评估(#2)并返回其值(#3)

但这就是我们想要的,以便从具有重复项的列表中获取唯一元素,我们希望只有当我们第一次遇到它们时才将它们.append放入新列表中。

所以我们真的想只在x不在used的时候评估used.append(x),也许如果有办法把这个None值变成truthy值,我们会没事的,对吧?

好吧,是的,这里是第二种类型的short-circuit运算符来玩的地方。

表达式x or y首先计算x;如果x为真,则其值为返回;否则,y被计算,结果值为返回

我们知道.append(x)永远是falsy,所以如果我们在他旁边加一个or,我们总是会得到下一部分。这就是为什么我们写:

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

所以我们可以评估used.append(x)并得到True作为结果,只有当表达式#2的第一部分是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 ll if x in l else (l.append(x) or l)

我们在哪里:

  1. x不在l中时,将x附加到l并返回l。感谢or语句,.append被评估,之后返回l
  2. xl中时,返回l未触及

Set是无序独特元素的集合。因此,您可以使用设置如下来获取唯一列表:

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

作为奖励,#0是获取每个值的唯一值和计数的简单方法:

from collections import Counterl = [u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow']c = Counter(l)

检查内容唯一性但保留原始顺序的解决方案:

def getUnique(self):notunique = self.readLines()unique = []for line in notunique: # Loop over contentappend = True # Will be set to false if line matches existing linefor existing in unique:if line == existing: # Line exists ? do not append and go to the next lineappend = Falsebreak # Already know file is unique, break loopif append: unique.append(line) # Line not found? add to listreturn unique

编辑:可能可以更有效地使用字典键来检查是否存在,而不是为每一行做一个完整的文件循环,我不会将我的解决方案用于大集。

要从列表中获取唯一值,请使用下面的代码:

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

<强>重要:如果列表中的任何项目不是可散列,则上述方法将不起作用,这对于可变类型来说是情况,例如列表字典

trends = [{'super':u'nowplaying'}, u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow']output = set(trends)Traceback (most recent call last):File "<stdin>", line 1, in <module>TypeError: unhashable type: 'dict'

这意味着你必须确保trends列表始终只包含可散列的项目,否则你必须使用更复杂的代码:

from copy import deepcopy
try:trends = [{'super':u'nowplaying'}, [u'PBS',], [u'PBS',], u'nowplaying', u'job', u'debate', u'thenandnow', {'super':u'nowplaying'}]output = set(trends)output = list(output)except TypeError:trends_copy = deepcopy(trends)while trends_copy:trend = trends_copy.pop()if trends_copy.count(trend) == 0:output.append(trend)print output

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

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

然后,如果你想唯一地将项目附加到列表中,你只需在UniqueList上调用append唯一。因为它继承自列表,它基本上就像一个列表,所以你可以使用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 1Uniquely appended 2Already contains 2Uniquely appended 3Already contains 3Uniquely appended 4

复制到列表:

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

打印:

[1, 2, 3, 4]

如果你想从列表中获取唯一的元素并保持它们的原始顺序,那么你可以使用Python标准库中的#0数据结构:

from collections import OrderedDict
def keep_unique(elements):return list(OrderedDict.fromkeys(elements).keys())
elements = [2, 1, 4, 2, 1, 1, 5, 3, 1, 1]required_output = [2, 1, 4, 5, 3]
assert keep_unique(elements) == required_output

事实上,如果您使用的是Python≥3.6,则可以使用普通dict

def keep_unique(elements):return list(dict.fromkeys(elements).keys())

在引入dicts的“紧凑”表示之后,这成为可能。检查它这里。尽管这“被认为是一个实现细节,不应该被依赖”。

您可以使用集合。为了清楚起见,我正在解释列表和集合之间的区别。列表是元素的有序集合。所以

    unicode_list=[u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job',u'debate', u'thenandnow']list_unique=list(set(unicode_list))print list_unique[u'nowplaying', u'job', u'debate', u'PBS', u'thenandnow']

但是:不要在命名变量时使用list/set。这会导致错误:例:而不是使用列表而不是unicode_list在上面的一个。

list=[u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job',u'debate', u'thenandnow']list_unique=list(set(list))print list_uniquelist_unique=list(set(list))TypeError: 'list' object is not callable

我很惊讶,到目前为止,还没有人给出一个直接的维持秩序的答案:

def unique(sequence):"""Generate unique items from sequence in the order of first occurrence."""seen = set()for value in sequence:if value in seen:continue
seen.add(value)
yield value

它将生成值,因此它不仅适用于列表,例如unique(range(10))。要获取列表,只需调用list(unique(sequence)),如下所示:

>>> list(unique([u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow']))[u'nowplaying', u'PBS', u'job', u'debate', u'thenandnow']

它要求每个项目都是可散列的,而不仅仅是可比的,但是Python中的大多数东西都是O(n)而不是O(n^2),所以在一个长列表中工作得很好。

除了前面的答案说您可以转换您的列表设置您可以这样做太

mylist = [u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenadnow']mylist = [i for i in set(mylist)]

输出将是

[u'nowplaying', u'job', u'debate', u'PBS', u'thenadnow']

但秩序不会被保留。

另一个简单的答案可能是(不使用集合)

>>> t = [v for i,v in enumerate(mylist) if mylist.index(v) == i][u'nowplaying', u'PBS', u'job', u'debate', u'thenadnow']

维持秩序:

# 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中快速获取任何一个的摘要。

鉴于

from collections import OrderedDict

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

代码

备选案文1-Aset(无序):

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

Python没有有序集合,但这里有某些方式来模拟一个。

备选案文2-OrderedDict(插入顺序):

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

备选案文3-dict(插入有序),Python 3.6+中默认。在此帖子中查看更多详细信息:

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

注意:列出的元素必须是可散列的。有关后一个例子的详细信息,请参阅博客文章。此外,请参阅R. Hettinger关于同一技术的帖子;顺序保持字典是从他早期的实现之一扩展而来的。另请参阅总排序

从列表中获取唯一元素

mylist = [1,2,3,4,5,6,6,7,7,8,8,9,9,10]

从集合中使用简单逻辑-集合是唯一的项目列表

mylist=list(set(mylist))
In [0]: mylistOut[0]: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

使用简单逻辑

newList=[]for i in mylist:if i not in newList:newList.append(i)
In [0]: mylistOut[0]: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

使用pop方法->pop删除最后一个或索引项并将其显示给用户。视频

k=0while k < len(mylist):if mylist[k] in mylist[k+1:]:mylist.pop(mylist[k])else:k=k+1
In [0]: mylistOut[0]: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

使用Numpy

import numpy as npnp.unique(mylist)
In [0]: mylistOut[0]: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

参考

使用set去重列表,以列表形式返回

def get_unique_list(lst):if isinstance(lst,list):return list(set(lst))

通过使用Python字典的基本属性:

inp=[u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow']d={i for i in inp}print d

输出将是:

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

set可以帮助您过滤掉列表中重复的元素。它适用于strinttuple元素,但如果您的列表包含dict或其他list元素,那么您最终将遇到TypeError异常。

这是一个通用的顺序保持解决方案来处理一些(不是全部)不可散列的类型:

def unique_elements(iterable):seen = set()result = []for element in iterable:hashed = elementif isinstance(element, dict):hashed = tuple(sorted(element.iteritems()))elif isinstance(element, list):hashed = tuple(element)if hashed not in seen:result.append(element)seen.add(hashed)return result