我有一个包含重复元素的排序列表,例如
>>> randList = [1, 2, 2, 3, 4, 4, 5]
>>> randList
[1, 2, 2, 3, 4, 4, 5]
我需要创建一个列表,以删除相邻的重复元素。我可以这样:
>>>> dupList = []
for num in nums:
if num not in dupList:
dupList.append(num)
但是我想通过列表理解来做到这一点。我尝试了以下代码:
>>> newList = []
>>> newList = [num for num in randList if num not in newList]
但是我得到的结果是if条件不起作用。
>>> newList
[1, 2, 2, 3, 4, 4, 5]
任何帮助将不胜感激。 谢谢!!
编辑1:鉴于我提供的数据,问题的措词似乎确实令人困惑。我正在使用的for循环将删除 all 重复项,但是由于我是对列表进行了预先排序,因此删除相邻重复项应该不会有问题。
答案 0 :(得分:2)
使用itertools.groupby
是删除相邻(且仅相邻)重复项的最简单方法,即使对于未排序的输入也是如此:
>>> from itertools import groupby
>>> [k for k, _ in groupby(randList)]
[1, 2, 3, 4, 5]
通过OrderedDict
,可以有效地实现在保留发生顺序的同时删除所有重复项。这同样适用于有序和无序输入:
>>> from collections import OrderedDict
>>> list(OrderedDict.fromkeys(randList))
[1, 2, 3, 4, 5]
答案 1 :(得分:1)
有三种方法可以实现删除已排序列表中相邻重复元素的目标,即删除所有重复元素:
groupby
(仅相邻元素,需要进行初始排序)OrderedDict
(已删除所有重复项)sorted(list(set(_)))
(删除所有重复项,并通过排序恢复顺序)。我使用以下方法比较了不同解决方案的运行时间:
from timeit import timeit
print('groupby:', timeit('from itertools import groupby; l = [x // 5 for x in range(1000)]; [k for k, _ in groupby(l)]'))
print('OrderedDict:', timeit('from collections import OrderedDict; l = [x // 5 for x in range(1000)]; list(OrderedDict.fromkeys(l))'))
print('Set:', timeit('l = [x // 5 for x in range(1000)]; sorted(list(set(l)))'))
> groupby: 78.83623623599942
> OrderedDict: 94.54144410200024
> Set: 65.60372123999969
请注意,set
方法是所有替代方法中最快的。
Python首先评估列表推导,然后将其分配给newList
,因此在执行列表推导期间无法引用它。为了说明,请考虑以下代码:
randList = [1, 2, 2, 3, 4, 4, 5]
newList = []
newList = [num for num in randList if print(newList)]
> []
> []
> []
> …
如果您尝试以下操作,这将变得更加明显:
# Do not initialize newList2
newList2 = [num for num in randList if print(newList2)]
> NameError: name 'newList2' is not defined
您可以通过将randList变成集合来删除重复项:
sorted(list(set(randlist)))
> [1, 2, 3, 4, 5]
请注意,这确实会删除所有个重复项(不仅仅是相邻的重复项),并且不会保留排序。前者也适用于您提出的带有循环的解决方案。
edit :添加了sorted
子句,以规定所需的顺序。
答案 2 :(得分:1)
我需要创建一个列表,以删除相邻的重复元素
请注意,您基于for
的循环解决方案将删除所有重复项,而不仅仅是相邻重复项。对此进行测试:
rand_list = [1, 2, 2, 3, 4, 4, 2, 5, 1]
根据您的规范,结果应为:
[1, 2, 3, 4, 2, 5, 1]
但您会得到
[1, 2, 3, 4, 5]
相反。
仅删除相邻重复项的可行解决方案是使用生成器:
def dedup_adjacent(seq):
prev = seq[0]
yield prev
for current in seq[1:]:
if current == prev:
continue
yield current
prev = current
rand_list = [1, 2, 2, 3, 4, 4, 2, 5, 1]
list(dedup_adjacent(rand_list))
=> [1、2、3、4、2、5、1]
答案 3 :(得分:1)
Python首先评估列表理解,然后将其分配给 newList ,因此您无法在执行列表理解期间引用它。
您可以通过两种方式删除重复项:-
1.使用for循环
rand_list = [1,2,2,3,3,4,5]
new_list=[]
for i in rand_list:
if i not in new_list:
new_list.append(i)
将列表转换为列表,然后再次将集合转换为列表,最后对新列表进行排序。
由于set以任何顺序存储值,因此当我们将set转换为list时,您需要对列表进行排序,以便以升序获得项目
rand_list = [1,2,2,3,3,4,5]
sets = set(rand_list)
new_list = list(sets)
new_list.sort()
答案 4 :(得分:0)
在此行newList = [num for num in randList if num not in newList]
中,首先将在右侧创建list
,然后将其分配给newList。这就是为什么每次您检查if num not in newList
都返回True的原因。因为newList
一直空着直到分配。
您可以尝试以下方法:
randList = [1, 2, 2, 3, 4, 4, 5]
new_list=[]
for i in randList:
if i not in new_list:
new_list.append(i)
print(new_list)
答案 5 :(得分:0)
操作过程中无法访问列表理解中的项目。列表理解中的项目只有在理解完成后才能访问。
对于大型列表,检查列表中的成员资格将很昂贵,尽管对内存的要求最少。相反,您可以附加到set
:
randList = [1, 2, 2, 3, 4, 4, 5]
def gen_values(L):
seen = set()
for i in L:
if i not in seen:
seen.add(i)
yield i
print(list(gen_values(randList)))
[1, 2, 3, 4, 5]
此算法已在第三方toolz
库中实现。在unique_everseen
文档中也称为itertools
食谱:
from toolz import unique
res = list(unique(randList))
答案 6 :(得分:-2)
由于列表已排序,因此使用set
是实现目标的快速方法,如下所示:
>>> randList = [1, 2, 2, 3, 4, 4, 5]
>>> randList
[1, 2, 2, 3, 4, 4, 5]
>>> remove_dup_list = list(set(randList))
>>> remove_dup_list
[1, 2, 3, 4, 5]
>>>