[英]Get unique values from a list in python [duplicate]
我想从以下列表中获取唯一值:
['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)
我应该使用更好的解决方案吗?
首先正确声明您的列表,用逗号分隔。 您可以通过将列表转换为集合来获取唯一值。
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)
为了与我将使用的类型保持一致:
mylist = list(set(mylist))
如果我们需要保持元素的顺序,这个怎么样:
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 开始,标准dict保留插入顺序。
在 3.7 版更改: 字典顺序保证是插入顺序。 此行为是 3.6 中 CPython 的实现细节。
所以这使我们能够使用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, [])
注意:请记住,我们获得的人类可读性越高,脚本的性能就越差。 除了特定于 python 3.7+ 的dict.from_keys
方法。
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
回答评论
因为@monica问了一个关于“这是如何工作的?”的好问题。 对于每个有问题的人来说。 我将尝试更深入地解释这是如何工作的以及这里发生了什么巫术;)
于是她先问:
我试图理解为什么
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) if x not in used
相同的逻辑,我们需要将这个.append
调用移动到列表.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
这基本上总是:
used
x
时计算结果为False
,x
未used
时计算为None
。 在这两种情况下( False
/ None
),这将被视为falsy
值,因此我们将得到一个空列表。
但是为什么当x
没有used
时它的计算结果是None
呢? 有人可能会问。
表达式
x and y
首先计算 x; 如果 x 为假,则返回其值; 否则,计算 y 并返回结果值。
因此,当x
未被使用时(即当它的True
)下一部分或表达式将被评估( used.append(x)
)并且它的值( None
)将被返回。
但这就是我们想要从具有重复项的列表中获取唯一元素的目的,我们希望仅当我们第一次遇到它们时才将它们.append
到新列表中。
所以我们真的想只在x
不在used
时评估used.append(x)
,也许如果有办法把这个None
值变成一个truthy
值,我们会没事的,对吧?
嗯,是的,这里是第二种类型的short-circuit
算子发挥作用的地方。
表达式
x or y
首先计算 x; 如果 x 为真,则返回其值; 否则,计算 y 并返回结果值。
我们知道.append(x)
永远是falsy
,所以如果我们只是在他falsy
加一个or
旁边,我们总是会得到下一部分。 这就是为什么我们写:
x not in used and (used.append(x) or True)
所以我们可以评估used.append(x)
并得到True
作为结果,只有当表达式的第一部分(x not in used)
是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
不变一个 Python 列表:
>>> a = ['a', 'b', 'c', 'd', 'b']
要获得独特的物品,只需将其转换为一个集合(如果需要,您可以再次将其转换回列表):
>>> b = set(a)
>>> print(b)
{'b', 'c', 'd', 'a'}
你的输出变量是什么类型?
Python集正是您所需要的。 像这样声明输出:
output = set() # initialize an empty set
并且您已准备好使用output.add(elem)
添加元素并确保它们是唯一的。
警告:集合不保留列表的原始顺序。
删除重复项的选项可能包括以下通用数据结构:
以下是有关在 Python 中快速获取其中任何一个的摘要。
给定的
from collections import OrderedDict
seq = [u"nowplaying", u"PBS", u"PBS", u"nowplaying", u"job", u"debate", u"thenandnow"]
代码
选项 1 - 一组(无序):
list(set(seq))
# ['thenandnow', 'PBS', 'debate', 'job', 'nowplaying']
选项 2 - Python 没有有序集,但这里有一些方法可以模仿(插入有序):
list(OrderedDict.fromkeys(seq))
# ['nowplaying', 'PBS', 'job', 'debate', 'thenandnow']
list(dict.fromkeys(seq)) # py36
# ['nowplaying', 'PBS', 'job', 'debate', 'thenandnow']
如果使用 Python 3.6+,建议使用最后一个选项。 在这篇文章中查看更多详细信息。
注意:列出的元素必须是hashable 。 请参阅此博客文章中有关后一个示例的详细信息。 此外,请参阅 R. Hettinger 关于相同技术的帖子; 保留顺序的 dict 是从他的早期实现之一扩展而来的。 另请参阅有关总排序的更多信息。
维持秩序:
# 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))
这是简单的解决方案 -
list=[u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow']
list=set(list)
从 List 中获取唯一元素
mylist = [1,2,3,4,5,6,6,7,7,8,8,9,9,10]
使用集合中的简单逻辑 - 集合是唯一的项目列表
mylist=list(set(mylist))
In [0]: mylist
Out[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]: mylist
Out[0]: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
使用 pop 方法 ->pop 删除最后一个或索引的项目并将其显示给用户。 视频
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]
使用 Numpy
import numpy as np
np.unique(mylist)
In [0]: mylist
Out[0]: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
如果您在代码中使用 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
...
PBS
debate
job
nowplaying
thenandnow
如果你真的想要一个普通的 Python 列表,你可以随时调用 list()。
但是,结果是自动排序的,从上面的代码片段可以看出。 如果需要保留列表顺序,请查看numpy unique 而不进行排序。
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
。
编辑
我应该注意,这不是一个好的方法,性能方面。 这只是一种仅使用列表压缩来实现它的方法。
作为奖励, Counter
是一种获取唯一值和每个值的计数的简单方法:
from collections import Counter
l = [u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow']
c = Counter(l)
通过使用 Python Dictionary 的基本属性:
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'])
首先,您给出的示例不是有效列表。
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
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
set
可以帮助您从列表中过滤掉重复的元素。 它适用于str
、 int
或tuple
元素,但如果您的列表包含dict
或其他list
元素,那么您最终会遇到TypeError
异常。
这是处理一些(不是全部)不可散列类型的通用顺序保留解决方案:
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
要从列表中获取唯一值,请使用以下代码:
trends = [u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow']
output = set(trends)
output = list(output)
重要提示:如果列表中的任何项目不可散列,则上述方法将不起作用,这是可变类型的情况,例如list或dict 。
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
如果您想从列表中获取唯一元素并保持其原始顺序,那么您可以使用 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())
在引入字典的“紧凑”表示之后,这成为可能。 在这里查看。 虽然这“被认为是一个实现细节,不应依赖”。
我很惊讶到目前为止没有人给出直接的顺序保留答案:
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']
def setlist(lst=[]):
return list(set(lst))
Set 是无序和唯一元素的集合。 因此,您可以使用如下设置来获取唯一列表:
unique_list = list(set([u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow']))
您可以使用集合。 为了清楚起见,我正在解释列表和集合之间的区别。 集合是唯一元素的无序集合。列表是元素的有序集合。 所以,
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。 它会导致错误: 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
output=[]
trends=list(set(trends))
我检查内容的唯一性但保留原始顺序的解决方案:
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
编辑:通过使用字典键来检查是否存在而不是为每一行执行整个文件循环可能会更有效,我不会将我的解决方案用于大集合。
使用 set 对列表进行重复数据删除,作为列表返回
def get_unique_list(lst):
if isinstance(lst,list):
return list(set(lst))
我知道这是一个老问题,但这是我独特的解决方案:类继承!:
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]
对于长数组
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)]
试试这个函数,它与您的代码类似,但它是一个动态范围。
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
使用以下函数:
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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.