从列表中删除所有出现的值?


377

在Python中,remove()将删除列表中第一个出现的值。

如何从列表中删除所有出现的值?

这就是我的想法:

>>> remove_values_from_list([1, 2, 3, 4, 2, 2, 3], 2)
[1, 3, 4, 3]

Answers:


505

功能方法:

Python 3.x

>>> x = [1,2,3,2,2,2,3,4]
>>> list(filter((2).__ne__, x))
[1, 3, 3, 4]

要么

>>> x = [1,2,3,2,2,2,3,4]
>>> list(filter(lambda a: a != 2, x))
[1, 3, 3, 4]

Python 2.x

>>> x = [1,2,3,2,2,2,3,4]
>>> filter(lambda a: a != 2, x)
[1, 3, 3, 4]

120
在filter + lambda上使用列表理解;前者除了通常更有效外,还更具可读性。
哈比人2009年

17
s /通常/通常在
哈比比特2009年

99
Habnabit的建议代码如下:[y for y in x if y != 2]
coredumperror

8
我不会称这种解决方案为最佳。在浏览代码时,列表理解更快,更容易理解。与其说Python,倒不如说是Perl方式。
Peter Nimroot '16

3
-1为直接调用__ne__。比较两个值比仅调用__eq__或调用__ne__其中一个要复杂得多。在这里它可能会正常工作,因为您只在比较数字,但是在一般情况下这是不正确的并且是错误。
阿兰·菲

211

您可以使用列表理解:

def remove_values_from_list(the_list, val):
   return [value for value in the_list if value != val]

x = [1, 2, 3, 4, 2, 2, 3]
x = remove_values_from_list(x, 2)
print x
# [1, 3, 4, 3]

7
您如何不检查就删除项目?
Alexander Ljungberg,2009年

18
这不会修改原始列表,但会返回一个新列表。
约翰Y

6
@Selinap:不,这是最佳选择,因为它只扫描一次列表。在您的原始代码中,in操作员和remove方法都扫描整个列表(直到找到匹配项为止),因此您最终以这种方式多次扫描了列表。
约翰·库格曼

4
@mhawke,@John Y:只需使用x [:] = ...而不是x =,它将是“就地”,而不仅仅是重新绑定名称“ x”(速度本质上是相同的,并且比x快得多) .remove可以!!!)。
Alex Martelli,2009年

10
我对此表示赞成,因为经过6年的Python开发,我仍然不理解Lambdas :)
Benjamin

107

如果必须修改原始列表,则可以使用切片分配,同时仍使用有效的列表理解(或生成器表达式)。

>>> x = [1, 2, 3, 4, 2, 2, 3]
>>> x[:] = (value for value in x if value != 2)
>>> x
[1, 3, 4, 3]

1
@Selinap:过滤器不会修改列表,它会返回一个新列表。
EM

过滤和列表理解不会修改列表。切片分配。和原始示例一样。
A. Coady

7
我喜欢它,因为它修改了x引用的列表。如果对该列表还有其他引用,它们也会受到影响。这与x = [ v for v in x if x != 2 ]提案相反,提案创建了一个新列表并更改了x以引用它,而原始列表保持不变。
汉尼斯

40

以更抽象的方式重复第一篇文章的解决方案:

>>> x = [1, 2, 3, 4, 2, 2, 3]
>>> while 2 in x: x.remove(2)
>>> x
[1, 3, 4, 3]

19
不过是O(n * n)。
汉尼斯

@Hannes会不是O(n),因为它只循环一次并同时删除了该项目?
五角大楼

1
考虑一下x = [1] * 10000 + [2] * 1000。循环体执行1000次,.remove()每次调用都必须跳过10000个元素。对我来说,这闻起来像O(n * n),但没有证据。我认为证明是假设列表中2的数量与其长度成正比。然后,该比例因子以big-O表示法消失。最好的情况是列表中仅2的常数,不是O(n ^ 2),而是O(2n),即O(n)。
汉尼斯

23

查看简单的解决方案

>>> [i for i in x if i != 2]

这将返回具有所有元素的列表x,而不2


11

上面的所有答案(除了Martin Andersson的答案)都会创建一个没有所需项目的新列表,而不是从原始列表中删除这些项目。

>>> import random, timeit
>>> a = list(range(5)) * 1000
>>> random.shuffle(a)

>>> b = a
>>> print(b is a)
True

>>> b = [x for x in b if x != 0]
>>> print(b is a)
False
>>> b.count(0)
0
>>> a.count(0)
1000

>>> b = a
>>> b = filter(lambda a: a != 2, x)
>>> print(b is a)
False

如果您对列表有其他参考,这可能很重要。

要修改列表,请使用如下方法

>>> def removeall_inplace(x, l):
...     for _ in xrange(l.count(x)):
...         l.remove(x)
...
>>> removeall_inplace(0, b)
>>> b is a
True
>>> a.count(0)
0

就速度而言,我的笔记本电脑上的结果是(全部在5000个条目列表中,其中删除了1000个条目)

  • 列表理解-〜400us
  • 过滤器-〜900us
  • .remove()循环-50毫秒

因此.remove循环要慢100倍左右........嗯,也许需要另一种方法。我发现最快的方法是使用列表理解,然后替换原始列表的内容。

>>> def removeall_replace(x, l):
....    t = [y for y in l if y != x]
....    del l[:]
....    l.extend(t)
  • removeall_replace()-450us

那么为什么不只是在旧地址下重新分配新列表呢?def remove_all(x, l): return [y for y in l if y != x]然后l = remove_all(3,l)
丹妮德

@Dannid这是第一个代码框中的第二个方法。它会创建一个新列表,而您没有修改旧列表。对该列表的任何其他引用将保持未过滤状态。
Paul S

嗯对 我对定义方法非常着迷,却忽略了您已经完成的简单分配。
丹妮德

7

你可以这样做

while 2 in x:   
    x.remove(2)

3
这是一个不好的解决方案,因为该列表必须遍历2 * n次,才能出现2次
。– cxxl

不建议在要遍历的列表中添加或删除。坏习惯恕我直言。
阿曼·马瑟

5

我以牺牲可读性为代价,认为此版本稍快一些,因为它不会迫使用户重新检查列表,因此无论如何,要做的删除操作完全相同:

x = [1, 2, 3, 4, 2, 2, 3]
def remove_values_from_list(the_list, val):
    for i in range(the_list.count(val)):
        the_list.remove(val)

remove_values_from_list(x, 2)

print(x)

根据我的测量,对于您在代码中显示的列表,此方法比列表理解方法(返回副本)慢36%。
djsmith 2012年

好,你注意到了。但是,因为我认为这可能会打消您的判断,所以我正在将我的版本与问题作者提出的第一个建议进行比较。
马丁·安德森

4

针对具有1.000.000元素的列表/数组的numpy方法和计时:

时间:

In [10]: a.shape
Out[10]: (1000000,)

In [13]: len(lst)
Out[13]: 1000000

In [18]: %timeit a[a != 2]
100 loops, best of 3: 2.94 ms per loop

In [19]: %timeit [x for x in lst if x != 2]
10 loops, best of 3: 79.7 ms per loop

结论: numpy比列表理解方法快27倍(在我的笔记本上)

PS,如果您想将常规Python列表转换lst为numpy数组:

arr = np.array(lst)

设定:

import numpy as np
a = np.random.randint(0, 1000, 10**6)

In [10]: a.shape
Out[10]: (1000000,)

In [12]: lst = a.tolist()

In [13]: len(lst)
Out[13]: 1000000

校验:

In [14]: a[a != 2].shape
Out[14]: (998949,)

In [15]: len([x for x in lst if x != 2])
Out[15]: 998949


3

要删除所有重复的事件并将其留在列表中:

test = [1, 1, 2, 3]

newlist = list(set(test))

print newlist

[1, 2, 3]

这是我用于欧拉计画的功能:

def removeOccurrences(e):
  return list(set(e))

2
我需要在具有250k值的矢量上执行此操作,它的工作原理就像一个魅力。
rschwieb 2013年

1
答案是:是的!而且我完全理解,对于一个称职的程序员来说,拥有一个向量长的听起来是否完全疯狂。我以数学家的身份处理那里的问题,而不用担心解决方案的优化,这可能导致解决方案的使用时间超过同等水平。(尽管我对超过5分钟的解决方案没有耐心。)
rschwieb 2013年

6
这将从列表中删除所有排序。
asmeurer

4
@JaredBurrows也许是因为它没有像目前那样回答问题,而是一个完全不同的问题。
drevicko 2014年

6
-1,这不是OP的问题的答案。这是删除重复项的解决方案,这是完全不同的事情。
Anoyz '16

2

我相信,如果您不关心列表顺序,如果您确实关心最终顺序,则可以从原始位置存储索引并以此来求助,这可能比任何其他方式都快。

category_ids.sort()
ones_last_index = category_ids.count('1')
del category_ids[0:ones_last_index]

2
我明白的地方去傻冒,但是这个代码将无法正常工作,因为你还需要开始索引,而不只是0
Shedokan

2
for i in range(a.count(' ')):
    a.remove(' ')

我相信要简单得多。


2
请修改您的答案,以提高清晰度。请明确说明您建议的代码的功能,原因以及建议的原因。也请正确格式化您的问题,以使代码与其余答案清晰可见。
Ortund

2

>>> x = [1, 2, 3, 4, 2, 2, 3]

之前已经发布的最简单有效的解决方案是

>>> x[:] = [v for v in x if v != 2]
>>> x
[1, 3, 4, 3]

应该使用较少的内存但速度较慢的另一种可能性是

>>> for i in range(len(x) - 1, -1, -1):
        if x[i] == 2:
            x.pop(i)  # takes time ~ len(x) - i
>>> x
[1, 3, 4, 3]

长度为1000和100000且具有10%匹配项的列表的计时结果:0.16 vs 0.25 ms,23 vs 123 ms。

长度为1000的计时

长度为100000的时间


1

从Python列表中删除所有出现的值

lists = [6.9,7,8.9,3,5,4.9,1,2.9,7,9,12.9,10.9,11,7]
def remove_values_from_list():
    for list in lists:
      if(list!=7):
         print(list)
remove_values_from_list()

结果: 6.9 8.9 3 5 4.9 1 2.9 9 12.9 10.9 11

或者,

lists = [6.9,7,8.9,3,5,4.9,1,2.9,7,9,12.9,10.9,11,7]
def remove_values_from_list(remove):
    for list in lists:
      if(list!=remove):
        print(list)
remove_values_from_list(7)

结果: 6.9 8.9 3 5 4.9 1 2.9 9 12.9 10.9 11


“ Python在函数中以“每个if循环嵌套”,准确度为100%!
rafiqul786 '16

您无需修改​​列表,只需打印元素即可。也将列表命名为列表令人困惑
kon psych

0

如果您没有内置的filter或不想使用多余的空间,并且需要线性解决方案...

def remove_all(A, v):
    k = 0
    n = len(A)
    for i in range(n):
        if A[i] !=  v:
            A[k] = A[i]
            k += 1

    A = A[:k]

0
hello =  ['h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd']
#chech every item for a match
for item in range(len(hello)-1):
     if hello[item] == ' ': 
#if there is a match, rebuild the list with the list before the item + the list after the item
         hello = hello[:item] + hello [item + 1:]
print hello

['你好,世界']


请尝试详细解释您的答案。
派拉德

0

我只是这样做了。我只是一个初学者。稍微更高级的程序员肯定可以编写这样的函数。

for i in range(len(spam)):
    spam.remove('cat')
    if 'cat' not in spam:
         print('All instances of ' + 'cat ' + 'have been removed')
         break

0

我们也可以使用del或进行就地删除所有内容pop

import random

def remove_values_from_list(lst, target):
    if type(lst) != list:
        return lst

    i = 0
    while i < len(lst):
        if lst[i] == target:
            lst.pop(i)  # length decreased by 1 already
        else:
            i += 1

    return lst

remove_values_from_list(None, 2)
remove_values_from_list([], 2)
remove_values_from_list([1, 2, 3, 4, 2, 2, 3], 2)
lst = remove_values_from_list([random.randrange(0, 10) for x in range(1000000)], 2)
print(len(lst))

现在提高效率:

In [21]: %timeit -n1 -r1 x = random.randrange(0,10)
1 loop, best of 1: 43.5 us per loop

In [22]: %timeit -n1 -r1 lst = [random.randrange(0, 10) for x in range(1000000)]
g1 loop, best of 1: 660 ms per loop

In [23]: %timeit -n1 -r1 lst = remove_values_from_list([random.randrange(0, 10) for x in range(1000000)]
    ...: , random.randrange(0,10))
1 loop, best of 1: 11.5 s per loop

In [27]: %timeit -n1 -r1 x = random.randrange(0,10); lst = [a for a in [random.randrange(0, 10) for x in
    ...:  range(1000000)] if x != a]
1 loop, best of 1: 710 ms per loop

正如我们所见,就地版本remove_values_from_list()不需要任何额外的内存,但是运行起来确实需要更多的时间:

  • 11秒就地删除值
  • 710毫秒的列表解析时间,可在内存中分配新列表

0

没有人发布关于时间和空间复杂性的最佳答案,所以我想我会试一试。这是一个解决方案,它消除了所有出现的特定值,而无需创建新数组,并且时间效率很高。缺点是元素不能保持顺序

时间复杂度:O(n)
附加空间复杂度:O(1)

def main():
    test_case([1, 2, 3, 4, 2, 2, 3], 2)     # [1, 3, 3, 4]
    test_case([3, 3, 3], 3)                 # []
    test_case([1, 1, 1], 3)                 # [1, 1, 1]


def test_case(test_val, remove_val):
    remove_element_in_place(test_val, remove_val)
    print(test_val)


def remove_element_in_place(my_list, remove_value):
    length_my_list = len(my_list)
    swap_idx = length_my_list - 1

    for idx in range(length_my_list - 1, -1, -1):
        if my_list[idx] == remove_value:
            my_list[idx], my_list[swap_idx] = my_list[swap_idx], my_list[idx]
            swap_idx -= 1

    for pop_idx in range(length_my_list - swap_idx - 1):
        my_list.pop() # O(1) operation


if __name__ == '__main__':
    main()

-1

关于速度!

import time
s_time = time.time()

print 'start'
a = range(100000000)
del a[:]
print 'finished in %0.2f' % (time.time() - s_time)
# start
# finished in 3.25

s_time = time.time()
print 'start'
a = range(100000000)
a = []
print 'finished in %0.2f' % (time.time() - s_time)
# start
# finished in 2.11

-3
p=[2,3,4,4,4]
p.clear()
print(p)
[]

仅适用于Python 3


2
可笑的是,这在所问问题的范围之内并且是正确的。
埃里希

我看不出它是正确的。这将从列表中删除所有项目,而不是所有出现的value
乔治

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.