Python 从一个列表中删除另一个列表中出现的所有元素

Python 从一个列表中删除另一个列表中出现的所有元素,python,list,Python,List,假设我有两个列表,l1和l2。我想执行l1-l2,它返回l1中不在l2中的所有元素 我可以想出一种简单的循环方法来实现这一点,但这将是非常低效的。什么是一个蟒蛇式的有效方法 例如,如果我有l1=[1,2,6,8]和l2=[2,3,5,8],l1-l2应该返回[1,6]Python有一个名为的语言特性,非常适合使这类事情变得非常简单。下面的语句完全按照您的要求执行,并将结果存储在l3: l3 = [x for x in l1 if x not in l2] l3将包含[1,6]一种方法是使用集合

假设我有两个列表,
l1
l2
。我想执行
l1-l2
,它返回
l1
中不在
l2
中的所有元素

我可以想出一种简单的循环方法来实现这一点,但这将是非常低效的。什么是一个蟒蛇式的有效方法


例如,如果我有
l1=[1,2,6,8]和l2=[2,3,5,8]
l1-l2
应该返回
[1,6]

Python有一个名为的语言特性,非常适合使这类事情变得非常简单。下面的语句完全按照您的要求执行,并将结果存储在
l3

l3 = [x for x in l1 if x not in l2]

l3
将包含
[1,6]
一种方法是使用集合:

>>> set([1,2,6,8]) - set([2,3,5,8])
set([1, 6])

但是,请注意,集合不会保留元素的顺序,并会导致删除任何重复的元素。元素还需要是可散列的。如果这些限制是可以容忍的,那么这通常是最简单、性能最高的选项。

使用Python集类型。那将是最具蟒蛇风格的。:)

而且,由于它是本地的,所以它也应该是最优化的方法

见:

(对于较旧的python)


扩展甜甜圈的答案和这里的其他答案,通过使用生成器理解而不是列表理解,以及使用
set
数据结构(因为
in
运算符在列表上是O(n),但在集合上是O(1),可以获得更好的结果

这是一个对你有用的函数:

def filter_list(full_list, excludes):
    s = set(excludes)
    return (x for x in full_list if x not in s)
结果将是一个iterable,它将惰性地获取过滤列表。如果您需要一个真正的列表对象(例如,如果您需要对结果执行
len()
),那么您可以很容易地构建如下列表:

filtered_list = list(filter_list(full_list, excludes))
替代解决方案:

reduce(lambda x,y : filter(lambda z: z!=y,x) ,[2,3,5,8],[1,2,6,8])
性能比较 比较Python 3.9.1和Python 2.7.16上这里提到的所有答案的性能

Python 3.9.1 答案按性能顺序列出:

  • 使用减法设置差分
    “-”运算-(每个循环91.3纳秒)

  • 使用
    set()

  • 基于
    设置的查找列表理解(每个循环366纳秒)

  • 普通列表上的列表理解-(每个循环489纳秒)

  • 生成器表达式,使用基于
    的查找设置
    并键入casting to
    list
    -(每个循环583 nsec):根据OP的要求,显式键入casting to list以获取最终对象,即
    list
    。如果生成器表达式被替换为list construction,它将与基于
    set
    的查找的列表理解相同

  • 使用
    filter()
    并显式键入cast到
    列表
    (需要像Python 3.x中那样显式键入cast,它返回迭代器)-(每个循环681 nsec)

  • 结合使用
    functools.reduce
    +
    过滤器
    -(每个循环3.36 usec):从Python 3.x开始显式键入casting到
    列表
    ,并返回迭代器。我们还需要导入
    functools
    以在Python 3.x中使用
    reduce

     mquadri$ python3 -m timeit "from functools import reduce; l1 = [1,2,6,8]; l2 = [2,3,5,8];" "list(reduce(lambda x,y : filter(lambda z: z!=y,x) ,l1,l2))"
     100000 loops, best of 5: 3.36 usec per loop
    
  • Python 2.7.16 答案按性能顺序列出:

  • 使用减法设置差分
    “-”运算-(每个循环0.0783 usec)

  • 使用
    set()

  • 基于
    设置的查找的列表理解(每个循环0.246 usec)

  • 普通列表上的列表理解-(每个循环0.372 usec)

  • 使用
    过滤器()

  • 生成器表达式,使用基于
    的查找设置
    并键入casting to
    list
    -(每个循环0.964):根据OP的要求,显式键入casting to list以获取最终对象,即
    list
    。如果生成器表达式被替换为list comprehension,它将与基于
    set
    的查找的列表理解相同

  • 使用
    功能工具的组合。减少
    +
    过滤器
    -(每个循环2.78 usec)

  • 使用{x for x in l2}或set(l2)获取集合,然后使用获取列表

    l2set = set(l2)
    l3 = [x for x in l1 if x not in l2set]
    
    基准测试代码:

    import time
    
    l1 = list(range(1000*10 * 3))
    l2 = list(range(1000*10 * 2))
    
    l2set = {x for x in l2}
    
    tic = time.time()
    l3 = [x for x in l1 if x not in l2set]
    toc = time.time()
    diffset = toc-tic
    print(diffset)
    
    tic = time.time()
    l3 = [x for x in l1 if x not in l2]
    toc = time.time()
    difflist = toc-tic
    print(difflist)
    
    print("speedup %fx"%(difflist/diffset))
    
    基准测试结果:

    0.0015058517456054688
    3.968189239501953
    speedup 2635.179227x    
    
    Python 3.8上的集合与列表理解基准 (与Moinuddin Quadri的基准相加)

    tldr:使用Arkku的set解决方案
    ,相比之下,它甚至比承诺的更快

    对照列表检查现有文件 在我的示例中,我发现使用Arkku的set解决方案比使用pythonic list comprehension(!)的速度快40倍(!),用于现实世界中对照列表检查现有文件名的应用程序

    列表理解: 壁时间:28.2秒

    设置 墙壁时间:689毫秒

    使用
    设置差异()
    可以使用获取集合中元素不在其他集合中的新集合。i、 e.
    set(A).差异(B)
    将返回set,其中项目出现在
    A
    中,但不在
    B
    中。例如:

    >>> set([1,2,6,8]).difference([2,3,5,8])
    {1, 6}
    
    l1, l2 = [1,2,6,8], [2,3,5,8]
    s2 = set(l2)  # Type-cast `l2` to `set`
    
    l3 = [x for x in l1 if x not in s2]
                                 #   ^ Doing membership checking on `set` s2
    
    这是一种函数方法,用于获取中提到的
    (使用算术减法
    -
    运算符进行集差)

    因为这些元素是无序的,所以您将失去初始列表中元素的顺序。(如果要维护元素的顺序,请继续阅读下一节)

    使用列表理解和基于
    set
    的查找 如果希望保持初始列表的顺序,那么基于答案的方法就可以了。但是,您可以获得更好的性能
     mquadri$ python3 -m timeit -s "l1 = [1,2,6,8]; l2 = set([2,3,5,8]);" "list(filter(lambda x: x not in l2, l1))"
     500000 loops, best of 5: 681 nsec per loop
    
     mquadri$ python3 -m timeit "from functools import reduce; l1 = [1,2,6,8]; l2 = [2,3,5,8];" "list(reduce(lambda x,y : filter(lambda z: z!=y,x) ,l1,l2))"
     100000 loops, best of 5: 3.36 usec per loop
    
    mquadri$ python -m timeit -s "l1 = set([1,2,6,8]); l2 = set([2,3,5,8]);" "l1 - l2"
    10000000 loops, best of 3: 0.0783 usec per loop
    
    mquadri$ mquadri$ python -m timeit -s "l1 = set([1,2,6,8]); l2 = set([2,3,5,8]);" "l1.difference(l2)"
    10000000 loops, best of 3: 0.117 usec per loop
    
     mquadri$ python -m timeit -s "l1 = [1,2,6,8]; l2 = set([2,3,5,8]);" "[x for x in l1 if x not in l2]"
     1000000 loops, best of 3: 0.246 usec per loop
    
     mquadri$ python -m timeit -s "l1 = [1,2,6,8]; l2 = [2,3,5,8];" "[x for x in l1 if x not in l2]"
     1000000 loops, best of 3: 0.372 usec per loop
    
     mquadri$ python -m timeit -s "l1 = [1,2,6,8]; l2 = set([2,3,5,8]);" "filter(lambda x: x not in l2, l1)"
     1000000 loops, best of 3: 0.593 usec per loop
    
     mquadri$ python -m timeit -s "l1 = [1,2,6,8]; l2 = set([2,3,5,8]);" "list(x for x in l1 if x not in l2)"
     1000000 loops, best of 3: 0.964 usec per loop
    
     mquadri$ python -m timeit "l1 = [1,2,6,8]; l2 = [2,3,5,8];" "reduce(lambda x,y : filter(lambda z: z!=y,x) ,l1,l2)"
     100000 loops, best of 3: 2.78 usec per loop
    
    l2set = set(l2)
    l3 = [x for x in l1 if x not in l2set]
    
    import time
    
    l1 = list(range(1000*10 * 3))
    l2 = list(range(1000*10 * 2))
    
    l2set = {x for x in l2}
    
    tic = time.time()
    l3 = [x for x in l1 if x not in l2set]
    toc = time.time()
    diffset = toc-tic
    print(diffset)
    
    tic = time.time()
    l3 = [x for x in l1 if x not in l2]
    toc = time.time()
    difflist = toc-tic
    print(difflist)
    
    print("speedup %fx"%(difflist/diffset))
    
    0.0015058517456054688
    3.968189239501953
    speedup 2635.179227x    
    
    %%time
    import glob
    existing = [int(os.path.basename(x).split(".")[0]) for x in glob.glob("*.txt")]
    wanted = list(range(1, 100000))
    [i for i in wanted if i not in existing]
    
    %%time
    import glob
    existing = [int(os.path.basename(x).split(".")[0]) for x in glob.glob("*.txt")]
    wanted = list(range(1, 100000))
    set(wanted) - set(existing)
    
    >>> set([1,2,6,8]).difference([2,3,5,8])
    {1, 6}
    
    l1, l2 = [1,2,6,8], [2,3,5,8]
    s2 = set(l2)  # Type-cast `l2` to `set`
    
    l3 = [x for x in l1 if x not in s2]
                                 #   ^ Doing membership checking on `set` s2
    
    >>> l1 = [1,2,6,8]
    >>> l2 = set([2,3,5,8])
    
    #     v  `filter` returns the a iterator object. Here I'm type-casting 
    #     v  it to `list` in order to display the resultant value
    >>> list(filter(lambda x: x not in l2, l1))
    [1, 6]
    
    l1=[1,2,6,8]
    l2=[2,3,5,8]
    r=[]
    for x in l1:
        if x in l2:
            continue
        r=r+[x]
    print(r)