Get unique values from a list in python
我想从以下列表中获取唯一值:
1 | [u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow'] |
我需要的输出是:
1 | [u'nowplaying', u'PBS', u'job', u'debate', u'thenandnow'] |
此代码有效:
1 2 3 4 5 | output = [] for x in trends: if x not in output: output.append(x) print output |
有没有更好的解决方案我应该使用?
首先正确声明您的列表,用逗号分隔。可以通过将列表转换为集合来获取唯一值。
1 2 3 | mylist = [u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow'] myset = set(mylist) print(myset) |
如果进一步将其用作列表,则应通过执行以下操作将其转换回列表:
1 | mynewlist = list(myset) |
另一种可能,可能更快的方法是从一开始就使用集合,而不是列表。那么您的代码应该是:
1 2 3 4 | output = set() for x in trends: output.add(x) print(output) |
正如已经指出的那样,这些装置不能维持原来的顺序。如果您需要,您应该查看订购的设备。
为了与我将使用的类型保持一致:
1 | mylist = list(set(mylist)) |
您的输出变量是什么类型?
python集就是您所需要的。这样声明输出:
1 | output = set([]) # initialize an empty set |
您可以使用
警告:集合不保留列表的原始顺序。
您提供的示例与Python中的列表不对应。它类似于嵌套的dict,这可能不是您想要的。
Python列表:
1 | a = ['a', 'b', 'c', 'd', 'b'] |
要获得唯一的项目,只需将其转换为一个集合(如果需要,可以将其重新转换为列表):
1 2 3 | b = set(a) print b >>> set(['a', 'b', 'c', 'd']) |
如果我们需要保持元素的顺序,那么这样做如何:
1 2 3 | 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)] |
还有一个使用
1 2 | 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, []) |
更新-2019年3月
第三种解决方案,这是一个很好的解决方案,但有点慢,因为
1 2 | 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月
另一个解决方案是使用
1 2 3 4 | 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, []) |
注意:请记住,我们获得的可读性越高,脚本的性能就越差。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | 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.6157128810882568 timeit.timeit('reduce(lambda l, x: l.append(x) or l if x not in l else l, mylist, [])', setup=setup) 1.8778090476989746 timeit.timeit('reduce(lambda l, x: l+[x] if x not in l else l, mylist, [])', setup=setup) 2.13108491897583 timeit.timeit('reduce(lambda l, x: l if x in l else l+[x], mylist, [])', setup=setup) 2.207760810852051 timeit.timeit('[x for i, x in enumerate(mylist) if i == mylist.index(x)]', setup=setup) 2.3621110916137695 |
回答意见
因为@monica问了一个很好的问题:"这是怎么工作的?"对于每个有问题的人来说。我将尝试更深入地解释这是如何运作的,以及这里发生了什么巫术;)
所以她首先问:
I try to understand why
unique = [used.append(x) for x in mylist if x is not working.
not in used]
好吧,它真的起作用了
1 2 3 4 5 6 7 | >>> 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] |
问题是,我们不能在
因此,为了将结果放入
但如果我们太幼稚了,只需要:
1 2 3 | >>> unique = [x for x in mylist if x not in used and used.append(x)] >>> print unique [] |
我们什么也得不到。
同样,这是因为
1 | x not in used and None |
这基本上总是:
在这两种情况下(
但是,当
因为这就是python的短路操作符的工作原理。
The expression
x and y first evaluates x; if x is false, its value is
returned; otherwise, y is evaluated and the resulting value is
returned.
因此,当不使用
但这正是我们想要的,为了从一个重复的列表中获得唯一的元素,我们只想在我们第一次遇到这些元素时,将它们添加到一个新的列表中。
所以我们只想在
是的,这里是第二类
The expression
x or y first evaluates x; if x is true, its value is
returned; otherwise, y is evaluated and the resulting value is
returned.
我们知道
1 | x not in used and (used.append(x) or True) |
因此,只有当表达的第一部分
在第二种方法中,使用
1 2 3 4 5 | (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 2 3 4 5 6 7 8 9 10 11 12 | # 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 |
订单无关紧要:
1 2 | # fastest-est -> --- 0.0035 seconds --- list(set(array)) |
这是一个简单的解决方案-
1 2 | list=[u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow'] list=set(list) |
从列表中获取唯一元素
1 | mylist = [1,2,3,4,5,6,6,7,7,8,8,9,9,10] |
Using Simple Logic from Sets - Sets are unique list of items
1 2 3 4 | mylist=list(set(mylist)) In [0]: mylist Out[0]: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] |
Using Simple Logic
1 2 3 4 5 6 7 | newList=[] for i in mylist: if i not in newList: newList.append(i) In [0]: mylist Out[0]: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] |
Using pop method
->pop removes the last or indexed item and displays that to user. video
1 2 3 4 5 6 7 8 9 | k=0 while k < len(mylist): if mylist[k] in mylist[k+1:]: mylist.pop(mylist[k]) else: k=k+1 In [0]: mylist Out[0]: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] |
Using Numpy
1 2 3 4 5 | import numpy as np np.unique(mylist) In [0]: mylist Out[0]: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] |
参考文献
集合-独特元素的无序集合。元素列表可以传递给集合的构造函数。所以,通过使用重复元素传递列表,我们使用唯一元素进行设置,然后将其转换回列表,然后使用唯一元素获取列表。关于性能和内存开销,我什么也不能说,但我希望,对于小的列表来说,这并不重要。
1 | list(set(my_not_unique_list)) |
简明扼要。
如果您在代码中使用了numpy(对于大量数据来说这可能是一个不错的选择),请签出numpy.unique:
1 2 3 4 5 | >>> 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不仅支持数字数据,还可以使用字符串数组。当然,结果是一个麻木的数组,但并不重要,因为它的行为仍然像一个序列:
1 2 3 4 5 6 7 8 | >>> for word in np.unique(wordsList): ... print word ... PBS debate job nowplaying thenandnow |
如果您真的想要一个普通的python列表,那么您可以随时调用list()。
但是,结果是自动排序的,从上面的代码片段中可以看到。如果需要保留列表顺序,请检查无排序的numpy unique。
仅使用列表压缩的相同顺序唯一列表。
1 2 3 4 5 6 7 8 | > 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] |
编辑
我要注意的是,这不是一个很好的方法,从性能上来说。这只是一种仅使用列表压缩实现它的方法。
通过使用python字典的基本属性:
1 2 3 | inp=[u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow'] d={i for i in inp} print d |
输出将是:
1 | set([u'nowplaying', u'job', u'debate', u'PBS', u'thenandnow']) |
首先,您给出的示例不是有效的列表。
1 | example_list = [u'nowplaying',u'PBS', u'PBS', u'nowplaying', u'job', u'debate',u'thenandnow'] |
假设上面是示例列表。然后,您可以使用下面的方法作为give-itertools示例文档,该示例文档可以返回唯一的值,并根据您的需要保留顺序。这里的iterable是示例清单
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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 |
1 2 3 4 5 6 | 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 |
以下是处理某些(不是全部)非哈希类型的常规订单保留解决方案:
1 2 3 4 5 6 7 8 9 10 11 12 13 | def unique_elements(iterable): seen = set() result = [] for element in iterable: hashed = element if 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 |
作为奖励,
1 2 3 | from collections import Counter l = [u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow'] c = Counter(l) |
1 2 | def setlist(lst=[]): return list(set(lst)) |
除了前面的答案,也就是说你可以把你的列表转换成集合,你也可以这样做。
1 2 | mylist = [u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenadnow'] mylist = [i for i in set(mylist)] |
输出将是
1 | [u'nowplaying', u'job', u'debate', u'PBS', u'thenadnow'] |
但秩序不会被保留。
另一个简单的答案可能是(不使用集合)
1 2 | >>> t = [v for i,v in enumerate(mylist) if mylist.index(v) == i] [u'nowplaying', u'PBS', u'job', u'debate', u'thenadnow'] |
我很惊讶到目前为止还没有人给出直接的订单保留答案:
1 2 3 4 5 6 7 8 9 10 | 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 |
它将生成值,因此它不仅可以与列表一起工作,例如
1 2 | >>> 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),所以对于长列表来说,它可以很好地工作。
要从列表中获取唯一值,请使用以下代码:
1 2 3 | trends = [u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow'] output = set(trends) output = list(output) |
重要:如果列表中的任何项都不可哈希(对于可变类型,例如list或dict),则上述方法将不起作用。
1 2 3 4 5 | 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' |
这意味着您必须确保
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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 |
您可以使用集合。为了清楚起见,我正在解释列表和集合之间的区别。集合是唯一元素的无序集合。列表是元素的有序集合。所以,
1 2 3 4 | 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列表。
1 2 3 4 5 | 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 |
使用set来消除列表重复,返回为列表
1 2 3 | def get_unique_list(lst): if isinstance(lst,list): return list(set(lst)) |
1 2 3 4 5 6 7 8 9 10 11 12 | from collections import OrderedDict seq = [u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow'] # Unordered (hashable items) list(set(seq)) # Out: ['thenandnow', 'PBS', 'debate', 'job', 'nowplaying'] # Order-preserving list(OrderedDict.fromkeys(seq)) # Out: ['nowplaying', 'PBS', 'job', 'debate', 'thenandnow'] |
或者在python 3.6+中:
1 2 3 | # Order-preserving list(dict.fromkeys(seq)) # Out: ['nowplaying', 'PBS', 'job', 'debate', 'thenandnow'] |
我的解决方案是检查内容的唯一性,但保留原始顺序:
1 2 3 4 5 6 7 8 9 10 11 | 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 |
编辑:通过使用字典键来检查是否存在,而不是对每行执行一个完整的文件循环,可能会更有效,我不会对大型集使用我的解决方案。
如果要从列表中获取唯一元素并保持其原始顺序,则可以使用Python标准库中的
1 2 3 4 5 6 7 8 9 | 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,那么可以使用plain
1 2 | def keep_unique(elements): return list(dict.fromkeys(elements).keys()) |
在引入了口述的"紧凑"表示之后,这就成为可能。在这里看看。尽管这"考虑了实施细节,不应依赖"。
集合是有序和唯一元素的集合。因此,可以使用如下设置获取唯一列表:
1 | unique_list = list(set([u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow'])) |
我知道这是一个古老的问题,但这里有我独特的解决方案:类继承!:
1 2 3 4 5 6 | class UniqueList(list): def appendunique(self,item): if item not in self: self.append(item) return True return False |
然后,如果要唯一地将项目附加到列表中,只需在单音列表中调用AppendUnique。因为它继承了一个列表,所以它基本上就像一个列表,所以您可以使用index()等函数,并且因为它返回true或false,所以您可以确定追加是成功的(唯一项)还是失败的(已经在列表中)。
要从列表中获取项目的唯一列表,请使用for循环将项目追加到单音列表(然后复制到列表)。
示例用法代码:
1 2 3 4 5 6 7 | 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) |
印刷品:
1 2 3 4 5 6 | Uniquely appended 1 Uniquely appended 2 Already contains 2 Uniquely appended 3 Already contains 3 Uniquely appended 4 |
正在复制到列表:
1 2 3 4 5 6 7 | unique = UniqueList() for each in [1,2,2,3,3,4]: unique.appendunique(each) newlist = unique[:] print newlist |
印刷品:
1 | [1, 2, 3, 4] |
长数组
1 2 3 4 5 6 7 8 9 10 11 12 | 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)] |
使用以下功能:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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 |
尝试这个函数,它类似于您的代码,但它是一个动态范围。
1 2 3 4 5 6 7 8 9 10 11 12 | 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 |