从python中的列表中获取唯一值[重复]
- 2024-12-11 08:47:00
- admin 原创
- 170
问题描述:
我想从以下列表中获取唯一值:
['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)
我应该使用更好的解决方案吗?
解决方案 1:
首先正确声明列表,以逗号分隔。您可以通过将列表转换为集合来获取唯一值。
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)
正如已经指出的那样,集合不保持原始顺序。如果您需要它,则应寻找有序集合实现(有关详细信息,请参阅此问题)。
解决方案 2:
为了与我使用的类型保持一致:
mylist = list(set(mylist))
解决方案 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)]
还有一个使用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, [])
更新-2020 年 12 月-也许是最好的方法!
从 python 3.7 开始,标准dict保留插入顺序。
在 3.7 版中更改:保证字典顺序与插入顺序一致。此行为是从 3.6 版开始的 CPython 实现细节。
因此这使我们能够进行dict.fromkeys()
重复数据删除!
注意:感谢@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, [])
注意:请记住,我们获得的可读性越高,脚本的性能就越差。除非dict.fromkeys()
是特定于 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
回答评论
因为@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
在左侧返回。
但如果我们太天真,只是这么做:
>>> 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
这基本上总是:
False
当x
在时计算为used
,None
当x
不在时,计算为used
。
在这两种情况下(False
/ None
),这将被视为falsy
值,结果我们将得到一个空列表。
但为什么None
当x
不在 时,它的计算结果为 呢used
?有人可能会问。
嗯,这是因为 Python 的短路运算符就是这样工作的。
该表达式
x and y
首先计算 x;如果 x 为假,则返回其值;否则,计算 y 并返回结果值。
因此,当x
未使用时(即当其时True
),将评估下一部分或表达式(used.append(x)
)并返回其值(None
) 。
但这就是我们想要的,为了从具有重复的列表中获取唯一元素,我们希望.append
只有当它们第一次出现时才将它们放入新列表中。
所以我们真正想要的是used.append(x)
仅在x
不在时进行评估used
,也许如果有办法将这个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
结果。(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
并返回l
当x
不在 时的情况l
。由于or
语句.append
被评估并l
在之后返回。l
当处于x
l
解决方案 4:
Python 列表:
>>> a = ['a', 'b', 'c', 'd', 'b']
要获得独特的项目,只需将其转换为一个集合(如果需要,您可以将其转换回列表):
>>> b = set(a)
>>> print(b)
{'b', 'c', 'd', 'a'}
解决方案 5:
您的输出变量是什么类型?
Python集合就是您所需要的。像这样声明输出:
output = set() # initialize an empty set
并且您已准备好添加元素output.add(elem)
并确保它们是唯一的。
警告:集合不会保留列表的原始顺序。
解决方案 6:
删除重复项的选项可能包括以下通用数据结构:
集合:无序、唯一元素
有序集:有序、唯一的元素
以下是在 Python 中快速获取其中任一个的总结。
鉴于
from collections import OrderedDict
seq = [u"nowplaying", u"PBS", u"PBS", u"nowplaying", u"job", u"debate", u"thenandnow"]
代码
选项 1 - A set
(无序):
list(set(seq))
# ['thenandnow', 'PBS', 'debate', 'job', 'nowplaying']
Python 没有有序集,但是这里有一些方法可以模仿有序集。
选项 2 - OrderedDict
(按顺序插入):
list(OrderedDict.fromkeys(seq))
# ['nowplaying', 'PBS', 'job', 'debate', 'thenandnow']
选项 3 - a (按顺序插入),Python 3.6+ 中的默认选项。请参阅此文章dict
中的更多详细信息:
list(dict.fromkeys(seq))
# ['nowplaying', 'PBS', 'job', 'debate', 'thenandnow']
注意:列出的元素必须是可哈希的。请参阅此博客文章中后一个示例的详细信息。此外,请参阅 R. Hettinger 关于同一技术的帖子;保序字典是从他的一个早期实现扩展而来的。另请参阅有关全序的更多信息。
解决方案 7:
维持秩序:
# 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))
解决方案 8:
从列表中获取唯一元素
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]
参考
解决方案 9:
如果你在代码中使用 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 without sort 。
解决方案 10:
set - 唯一元素的无序集合。元素列表可以传递给 set 的构造函数。因此,传递具有重复元素的列表,我们获取具有唯一元素的 set 并将其转换回列表,然后获取具有唯一元素的列表。我无法谈论性能和内存开销,但我希望,对于小列表来说,这不是那么重要。
list(set(my_not_unique_list))
簡單又短小。
解决方案 11:
仅使用列表压缩的相同顺序唯一列表。
> 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
列表中的第一个。
编辑
我应该指出,从性能角度来看,这不是一个好方法。这只是一种仅使用列表压缩来实现的方法。
解决方案 12:
首先,您给出的例子不是一个有效的列表。
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
解决方案 13:
作为奖励,Counter
这是一种获取唯一值和每个值的计数的简单方法:
from collections import Counter
l = [u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow']
c = Counter(l)
解决方案 14:
通过使用 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'])
解决方案 15:
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
解决方案 16:
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
解决方案 17:
def setlist(lst=[]):
return list(set(lst))
解决方案 18:
如果您想从列表中获取唯一元素并保持其原始顺序,那么您可以使用OrderedDict
Python 标准库中的数据结构:
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 dict
:
def keep_unique(elements):
return list(dict.fromkeys(elements).keys())
在引入“紧凑”的字典表示后,这已成为可能。在这里查看。尽管这“被视为实现细节,不应依赖”。
解决方案 19:
要从列表中获取唯一值,请使用以下代码:
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
解决方案 20:
令我惊讶的是,到目前为止还没有人给出直接的保序答案:
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),因此对于长列表也可以正常工作。
解决方案 21:
除了前面提到的可以将列表转换为集合的答案之外,您还可以通过这种方式进行转换
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']
解决方案 22:
在代码开始时,只需将输出列表声明为空:
output=[]
除了您的代码之外,您还可以使用此代码
trends=list(set(trends))
解决方案 23:
您可以使用集合。为了清楚起见,我正在解释列表和集合之间的区别。集合是唯一元素的无序集合。列表是元素的有序集合。所以,
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 来命名变量。这将导致错误:例如:在上面的例子中,应该使用 list 而不是 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
解决方案 24:
使用 set 对列表进行去重,并以列表形式返回
def get_unique_list(lst):
if isinstance(lst,list):
return list(set(lst))
解决方案 25:
Set 是无序且唯一元素的集合。因此,你可以按如下方式使用 set 来获取唯一列表:
unique_list = list(set([u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow']))
解决方案 26:
我的解决方案是检查内容的唯一性但保留原始顺序:
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
编辑:使用字典键来检查是否存在可能会更有效,而不是对每一行进行整个文件循环,我不会对大型集合使用我的解决方案。
解决方案 27:
我知道这是一个老问题,但这是我独特的解决方案:类继承!:
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]
解决方案 28:
对于长数组
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)]
解决方案 29:
尝试这个函数,它与您的代码类似,但它是一个动态范围。
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
解决方案 30:
使用以下函数:
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