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纳秒)
的查找设置并键入casting tolist
-(每个循环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
使用减法设置差分
“-”运算-(每个循环0.0783 usec)
set()
设置的查找的列表理解(每个循环0.246 usec)
过滤器()
的查找设置并键入casting tolist
-(每个循环0.964):根据OP的要求,显式键入casting to list以获取最终对象,即list
。如果生成器表达式被替换为list comprehension,它将与基于set
的查找的列表理解相同
功能工具的组合。减少+过滤器
-(每个循环2.78 usec)
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)