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

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

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

我需要的输出是:

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

此代码工作:

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

有没有更好的解决scheme,我应该使用?

首先正确申报你的名单,用逗号分隔。 您可以通过将列表转换为一组来获得唯一的值。

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

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

 mynewlist = list(myset) 

另一种可能性,可能更快将是从一开始,而不是一个列表使用一套。 那么你的代码应该是:

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

正如已经指出的那样,集合不保持原来的顺序。 如果你需要的话,你应该查看有序集 。

为了与我将使用的types一致:

 mylist = list(set(mylist)) 

您提供的示例与Python中的列表不对应。 它类似于一个嵌套的字典,这可能不是你想要的。

一个Python列表:

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

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

 b = set(a) print b >>> set(['a', 'b', 'c', 'd']) 

你的输出variables是什么types?

Python 集合是你刚才需要的。 声明这样的输出:

 output = set([]) # initialize an empty set 

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

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

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

 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)] 

还有一个解决scheme使用reduce和没有临时used变种。

 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, []) 

更新 – 2016年10月1日

另一个解决scheme是使用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, []) 

注意:请记住,我们得到更多的可读性,更多的脚本是不正确的。

 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.4188511371612549 timeit.timeit('[x for x in mylist if x not in used and (used.append(x) or True)]', setup='used = [];'+setup) 0.8063139915466309 timeit.timeit('reduce(lambda l, x: l.append(x) or l if x not in l else l, mylist, [])', setup=setup) 2.216820001602173 timeit.timeit('reduce(lambda l, x: l+[x] if x not in l else l, mylist, [])', setup=setup) 2.948796033859253 timeit.timeit('reduce(lambda l, x: l if x in l else l+[x], mylist, [])', setup=setup) 2.9785239696502686 

回答评论

因为@monica问了一个关于“这是怎么工作的”的好问题。 对于有问题的人来说, 我会尝试给出更深入的解释,说明这是如何工作的,以及这里发生的魔法事情;)

所以她首先问:

我试图理解为什么unique = [used.append(x) for x in mylist if x not in used] is not working。

那么它实际上是工作

 >>> 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] 

问题是,我们只是没有获得所需的结果内uniquevariables,但只在usedvariables。 这是因为在列表理解过程中, .append修改usedvariables并返回None

所以为了得到结果到uniquevariables,并仍然使用相同的逻辑与.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 ,它给我们的逻辑expression式看起来如下:

 x not in used and None 

这基本上总是:

  1. xused时评估为False
  2. 在不used x情况下评估为None

而在这两种情况下( False / None ),都将被视为falsy值,因此我们会得到一个空的列表。

但是,当x不在used为什么这个计算结果为None ? 有人可能会问。

那么这是因为这是Python的短路操作工作 。

expression式x and y首先评估x; 如果x为假,则返回其值; 否则,评估y并返回结果值。

所以当x不在使用(即当它是True ,下一部分或expression式将被评估used.append(x)和它的值None将被返回。

但是这就是我们想要从列表中获得重复的唯一元素,我们希望只有当我们碰到了第一个时间的时候,才把它们添加到新列表中。

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

那么,是的,这是第二种types的short-circuit操作员来玩的地方。

expression式x or y首先评估x; 如果x为真,则返回其值; 否则,评估y并返回结果值。

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

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

所以我们可以评估 used.append(x)只有当expression式的第一部分(x not in used)True 才能得到True

减法法的第二种方法可以看到类似的方式。

 (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) 

我们在哪里:

  1. x附加到l并在x不在l时返回l 。 感谢or语句.append被评估, l被返回。
  2. xl时,返回l不变

设置 – 独特元素的无序集合。 元素列表可以传递给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

编辑

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

如果您在代码中使用numpy(对于大量数据来说这可能是一个不错的select),请查看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不仅支持数字数据,string数组也是可能的。 当然,结果是一个numpy数组,但它并不重要,因为它仍然像一个序列:

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

如果你真的想要一个香草Python列表,你总是可以调用list()。

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

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

 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') --> ABCD # unique_everseen('ABBCcAD', str.lower) --> ABCD 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 get_distinct(original_list): distinct_list = [] for each in original_list: if each not in distinct_list: distinct_list.append(each) return distinct_list 
 def setlist(lst=[]): return list(set(lst)) 

作为奖励, Counter是一个简单的方法来获得每个值的唯一值和计数:

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

除了之前的答案,也就是说你可以将你的列表转换为集合,你也可以这样做

 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'] 

尽pipe命令不会被保留。

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

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

如果你需要维护秩序,这是一个单行的:

 [x for i, x in enumerate(array) if x not in array[0:i]] 

编辑:使用这一个class轮维护订单的成本高…

 array = [round(random.random()*10) for _ in range(100000)] # maintain order [x for i, x in enumerate(array) if x not in array[0:i]] #=> --- 14.416885137557983 seconds --- uniq = [] [uniq.append(x) for x in array if x not in uniq] uniq #=> --- 0.011909008026123047 seconds --- # doesn't maintain order list(set(array)) #=> --- 0.003480195999145508 seconds --- 
  1. 在你的代码开始时,只需将你的输出列表声明为空: output=[]
  2. 代替你的代码,你可以使用这个代码trends=list(set(trends))

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

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

重要提示:如果列表中的任何项目不可哈希 ( 可变types,例如列表或字典) ,上述方法将不起作用。

 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列表总是只包含可sorting的项目,否则你必须使用更复杂的代码:

 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 

你可以使用集合。 只是要清楚,我正在解释一个列表和一个集合之间的区别。 集合是无序集合的唯一元素。列表是有序集合的元素。 所以,

  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命名variables。 它会导致错误:EX:而不是使用列表而不是unicode_list在上面的一个。

 list=[u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job',u'debate', u'thenandnow'] list_unique=list(set(list)) print list_unique list_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),所以将工作得很好,一个长长的清单。

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

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

我知道这是一个古老的问题,但这是我独特的解决scheme:类inheritance!

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

然后,如果您想要将项目唯一地附加到列表,则只需在UniqueList上调用appendunique。 因为它是从一个列表inheritance的,所以它基本上就像一个列表,所以你可以使用像index()等函数。因为它返回true或者false,所以你可以发现是否添加成功(unique item)或者失败列表)。

要从列表中获取唯一的项目列表,请使用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] 

对于长arrays

 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)] 

如果你想从列表中获得独特的元素并保持原来的顺序,那么你可以使用Python标准库中的OrderedDict数据结构:

 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()) 

在引入“紧凑”的字典表示之后,这成为可能。 看看这里 。 虽然这是“考虑实施的细节,不应该依赖”。

我的解决scheme检查内容的唯一性,但保持原来的顺序:

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

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

使用以下function:

 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 

试试这个函数,它和你的代码类似,但是它是一个dynamic范围。

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