我想从以下列表中获取唯一值:
['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, [])
更新 - 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, [])
注意:请记住,我们得到的文字更加可读,脚本的性能更差。
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问了一个很好的问题:“这是如何工作的?”。对于每个遇到困难的人。我将尝试对此进行更深入的解释,以及在这里发生了什么魔术;)
所以她首先问:
我试着理解为什么为什么
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
这基本上总是:
False
时, x
在used
, used
x
时,结果为None
。 并且在两种情况下( False
/ None
),这都将被视为falsy
值,结果将得到一个空列表。
但是,为什么在不used
x
时将其评估为None
呢?有人会问。
表达式
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 为 true,则返回其值;否则,将评估 y 并返回结果值。
我们知道.append(x)
永远都是falsy
,因此,如果我们仅在他旁边添加一个or
旁边,我们将始终得到下一个部分。这就是为什么我们这样写:
x not in used and (used.append(x) or True)
因此, 仅当表达式的第一部分(x not in used)
为True
时 ,我们才能评估 used.append(x)
并获得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
不变