无法使用带有if条件的列表理解从现有列表中创建重复列表

时间:2018-07-05 11:18:58

标签: python list if-statement list-comprehension

我有一个包含重复元素的排序列表,例如

>>> 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 重复项,但是由于我是对列表进行了预先排序,因此删除相邻重复项应该不会有问题。

7 个答案:

答案 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)
  1. 将列表转换为列表,然后再次将集合转换为列表,最后对新列表进行排序。
    由于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]
>>>