从另一个列表中删除一个列表中的所有值?

ari*_*iel 114 python list

我正在寻找一种方法来从另一个列表中删除列表中的所有值.

像这样的东西:

a = range(1,10)  
a.remove([2,3,7])  
print a  
a = [1,4,5,6,8,9]  
Run Code Online (Sandbox Code Playgroud)

YOU*_*YOU 126

>>> a = range(1, 10)
>>> [x for x in a if x not in [2, 3, 7]]
[1, 4, 5, 6, 8, 9]
Run Code Online (Sandbox Code Playgroud)

  • 如果我有一个列表`[1,2,2,2,3,4]`和一个子列表`[2,3]`,那么结果应该是`[1,2,2,4]`,是否有Pythonic方法来做到这一点? (14认同)

aru*_*ngh 44

如果您没有重复值,则可以使用设置差异.

x = set(range(10))
y = x - set([2, 3, 7])
# y = set([0, 1, 4, 5, 6, 8, 9])
Run Code Online (Sandbox Code Playgroud)

然后转换回列表,如果需要的话.

  • 另外,如果您的原始列表x有重复项,则在set()操作之后,只保存一个. (4认同)
  • 请注意,这将随机播放列表. (3认同)

The*_*her 43

我正在寻找快速的方法来完成这个主题,所以我用建议的方法做了一些实验.我对结果感到惊讶,所以我想和你分享.

实验是使用pythonbenchmark工具完成的

a = range(1,50000) # Source list
b = range(1,15000) # Items to remove
Run Code Online (Sandbox Code Playgroud)

结果:

 def comprehension(a, b):
     return [x for x in a if x not in b]
Run Code Online (Sandbox Code Playgroud)

5次尝试,平均时间12.8秒

def filter_function(a, b):
    return filter(lambda x: x not in b, a)
Run Code Online (Sandbox Code Playgroud)

5次尝试,平均时间12.6秒

def modification(a,b):
    for x in b:
        try:
            a.remove(x)
        except ValueError:
            pass
    return a
Run Code Online (Sandbox Code Playgroud)

5次尝试,平均时间0.27秒

def set_approach(a,b):
    return list(set(a)-set(b))
Run Code Online (Sandbox Code Playgroud)

5次尝试,平均时间0.0057

此外,我还为最后两个函数使用更大的输入大小进行了另一次测量

a = range(1,500000)
b = range(1,100000)
Run Code Online (Sandbox Code Playgroud)

结果如下:

对于修改(删除方法) - 平均时间为252秒对于设置方法 - 平均时间为0.75

因此,您可以看到使用集合的方法明显快于其他方法.是的,它没有保留类似的物品,但是如果你不需要它 - 它适合你.列表理解与使用过滤功能之间几乎没有区别.使用'remove'要快50倍,但它会修改源列表.最好的选择是使用套装 - 它比列表理解快1000倍!

  • 很好的答案,谢谢!集合要快得多,因为找到项目的时间是线性的,因为Python集合被实现为哈希表。因此,要删除已设置的项目,无需花费时间来定位该项目,而在列表中必须首先找到该项目。 (2认同)

Yar*_*lav 26

a = range(1,10)
itemsToRemove = set([2, 3, 7])
b = filter(lambda x: x not in itemsToRemove, a)
Run Code Online (Sandbox Code Playgroud)

要么

b = [x for x in a if x not in itemsToRemove]
Run Code Online (Sandbox Code Playgroud)

不要lambda在理解内部或内部创建集合.如果你这样做,它将在每次迭代时重新创建,完全不使用集合.


Joh*_*ooy 7

最简单的方法是

>>> a = range(1, 10)
>>> for x in [2, 3, 7]:
...  a.remove(x)
... 
>>> a
[1, 4, 5, 6, 8, 9]
Run Code Online (Sandbox Code Playgroud)

这里可能存在的一个问题是,每次调用remove()时,所有项都会在列表中向下移动以填充漏洞.因此,如果a增长非常大,这将最终变得非常缓慢.

这种方式构建了一个全新的列表.优点是我们避免了第一种方法的所有改组

>>> removeset = set([2, 3, 7])
>>> a = [x for x in a if x not in removeset]
Run Code Online (Sandbox Code Playgroud)

如果要进行a适当的修改,只需要进行一处小改动

>>> removeset = set([2, 3, 7])
>>> a[:] = [x for x in a if x not in removeset]
Run Code Online (Sandbox Code Playgroud)

  • "简单"不是*错误*的借口. (3认同)

Anu*_*yal 6

其他人已经提出了在过滤后制作新列表的方法,例如

newl = [x for x in l if x not in [2,3,7]]
Run Code Online (Sandbox Code Playgroud)

要么

newl = filter(lambda x: x not in [2,3,7], l) 
Run Code Online (Sandbox Code Playgroud)

但是根据你的问题看起来你想要就地修改你可以做到这一点,如果原始列表很长并且要删除的项目也会更快

l = range(1,10)
for o in set([2,3,7,11]):
    try:
        l.remove(o)
    except ValueError:
        pass

print l
Run Code Online (Sandbox Code Playgroud)

输出:[1,4,5,6,8,9]

我正在检查ValueError异常,因此即使项目不在原始列表中也能正常工作.

此外,如果您不需要就地修改解决方案S.Mark更简单.

  • 是的,[:]可以使用,但不明显它会更快,因为删除我的代码的值很少的长列表会快得多,例如try list to remove = [1] :) (2认同)

gho*_*g74 5

>>> a=range(1,10)
>>> for i in [2,3,7]: a.remove(i)
...
>>> a
[1, 4, 5, 6, 8, 9]

>>> a=range(1,10)
>>> b=map(a.remove,[2,3,7])
>>> a
[1, 4, 5, 6, 8, 9]
Run Code Online (Sandbox Code Playgroud)