如何使用列表推导式从列表中删除重复项?我有以下代码:
a = [1, 2, 3, 3, 5, 9, 6, 2, 8, 5, 2, 3, 5, 7, 3, 5, 8]
b = []
b = [item for item in a if item not in b]
但是它并不起作用,只是生成了相同的列表。为什么会生成相同的列表?
如何使用列表推导式从列表中删除重复项?我有以下代码:
a = [1, 2, 3, 3, 5, 9, 6, 2, 8, 5, 2, 3, 5, 7, 3, 5, 8]
b = []
b = [item for item in a if item not in b]
但是它并不起作用,只是生成了相同的列表。为什么会生成相同的列表?
由于在运行时 b
不包含任何元素,因此它生成了一个相同的列表。
你需要的是这个:
>>> a = [1, 2, 3, 3, 5, 9, 6, 2, 8, 5, 2, 3, 5, 7, 3, 5, 8]
>>> b = []
>>> [b.append(item) for item in a if item not in b]
[None, None, None, None, None, None, None, None]
>>> b
[1, 2, 3, 5, 9, 6, 8, 7]
如果你不介意使用与列表推导式不同的技巧,你可以使用集合:
>>> a = [1, 2, 3, 3, 5, 9, 6, 2, 8, 5, 2, 3, 5, 7, 3, 5, 8]
>>> b = list(set(a))
>>> print b
[1, 2, 3, 5, 6, 7, 8, 9]
set
慢,但如果您使用的是3.6+版本,则速度不会太慢(如果您使用的是OrderedDict
3.5及更早版本,则会有更大的影响;运行时间增加了超过3倍,而使用普通dict
的3.6+版本仅增加了约66%的运行时间)。 - ShadowRanger使用 a
中的值作为键创建一个 dict
,然后使用 keys
方法。
b = dict([(i, 1) for i in a]).keys()
或者使用一个集合:
b = [i for i in set(a)]
if item not in b
始终为True
。只有在列表生成后,才将新的非空列表分配给变量b。>>> from itertools import groupby
>>> a = [1, 2, 3, 3, 5, 9, 6, 2, 8, 5, 2, 3, 5, 7, 3, 5, 8]
>>> [k for k, _ in groupby(sorted(a, key=lambda x: a.index(x)))]
[1, 2, 3, 5, 9, 6, 8, 7]
如果您不关心值在原始列表中的顺序,可以省略key参数,例如:
>>> [k for k, _ in groupby(sorted(a))]
[1, 2, 3, 5, 6, 7, 8, 9]
你可以使用 groupby
来实现一些酷炫的功能。要识别出出现多次的项:
>>> [k for k, v in groupby(sorted(a)) if len(list(v)) > 1]
[2, 3, 5, 8]
>>> {k: len(list(v)) for k, v in groupby(sorted(a))}
{1: 1, 2: 3, 3: 4, 5: 4, 6: 1, 7: 1, 8: 2, 9: 1}
Python的itertools模块中有一些非常有用的函数:其中包括chain
、tee
和product
等。
>>> a = [10,20,30,20,10,50,60,40,80,50,40,0,100,30,60]
>>> [a.pop(a.index(i, a.index(i)+1)) for i in a if a.count(i) > 1]
>>> print(a)
对于Python 3.6+,相比Niek de Klein的绝大部分优秀解决方案(其主要缺陷是会丢失输入顺序),有一种更好的改进。由于dict
现在是插入有序的,你只需要这样做:
b = list(dict.fromkeys(a))
On earlier Python, you'd do:
from collections import OrderedDict
b = list(OrderedDict.fromkeys(a))
虽然 OrderedDict
被移至 C 层,但它仍然没有那么快,因为它保留了许多用于支持重新排序操作的开销,而 dict
不支持这些操作并避免了这些开销。
>>> from itertools import groupby
>>> repeated_items = [2,2,2,2,3,3,3,3,4,5,1,1,1]
>>> [
... next(group)
... for _, group in groupby(
... repeated_items,
... key=repeated_items.index
... )
... ]
[2, 3, 4, 5, 1]
index
调用使其成为O(n²)
,并且假设输入已经分组(它不适用于[2,1,2]
)。您可以使用修改后的Schwartzian变换(需要from itertools import count, groupby
)解决这两个问题,并仍然保留输入顺序:[v for v, _ in sorted([next(grp) for _, grp in groupby(sorted(zip(repeated_items, count())), key=lambda x: x[0])], key=lambda x: x[1])]
。可能不值得麻烦,但我喜欢一些由itertools
驱动的疯狂。 - ShadowRanger
if item not in b
时,列表b
当前是空的。列表推导式会在内存中完成,结果最终被赋值给b
。 - Felix Klingunique_everseen
迭代器。使用方法如下:b = list(unique_everseen(a))
。 - Lauritz V. Thaulowx = y
时,y
首先被评估,然后结果被分配给x
。但在评估y
期间,x
不会被修改。如果你使用b = list(item for item in a if item not in b)
,你会有同样的疑问吗? - Felix Kling