从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]
问题是,我们只是没有获得所需的结果内unique
variables,但只在used
variables。 这是因为在列表理解过程中, .append
修改used
variables并返回None
。
所以为了得到结果到unique
variables,并仍然使用相同的逻辑与.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
这基本上总是:
-
x
在used
时评估为False
, - 在不
used
x
情况下评估为None
。
而在这两种情况下( False
/ None
),都将被视为falsy
值,因此我们会得到一个空的列表。
但是,当x
不在used
为什么这个计算结果为None
? 有人可能会问。
那么这是因为这是Python的短路操作工作 。
expression式
x and y
首先评估x; 如果x为假,则返回其值; 否则,评估y并返回结果值。
所以当x
不在使用(即当它是True
) ,下一部分或expression式将被评估( used.append(x)
)和它的值( None
)将被返回。
但是这就是我们想要从列表中获得重复的唯一元素,我们希望只有当我们碰到了第一个时间的时候,才把它们添加到新列表中。
所以我们真的只想在x
不used
时候评估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)
我们在哪里:
- 将
x
附加到l
并在x
不在l
时返回l
。 感谢or
语句.append
被评估,l
被返回。 - 当
x
在l
时,返回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 ---
- 在你的代码开始时,只需将你的输出列表声明为空:
output=[]
- 代替你的代码,你可以使用这个代码
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