Answers:
Python具有称为List Comprehensions的语言功能,非常适合使这种事情变得非常容易。以下语句完全满足您的要求,并将结果存储在l3
:
l3 = [x for x in l1 if x not in l2]
l3
将包含[1, 6]
。
in
运算符在列表上的效率不高。 in
列表上的是O(n),而in
集合上的是O(1)。但是,除非您使用了成千上万个元素或更多,否则您不太可能注意到差异。
l3 = [x for x in l1 if x not in set(l2)]
?我确定是否set(l2)
会被多次调用。
l2s = set(l2)
然后说l3 = [x for x in l1 if x not in l2s]
。稍微容易些。
一种方法是使用集合:
>>> set([1,2,6,8]) - set([2,3,5,8])
set([1, 6])
l1
,这可能是不希望的副作用。
timeit.timeit('a = [1,2,3,4]; b = [1,3]; c = [i for i in a if a not in b]', number=100000) -> 0.12061533199999985
timeit.timeit('a = {1,2,3,4}; b = {1,3}; c = a - b', number=100000) -> 0.04106225999998969
。因此,如果性能是一个重要因素,那么这个答案可能会更合适(并且如果您不关心重复或订购)
或者,您也可以将filter
其与lambda表达式配合使用以获取所需的结果。例如:
>>> 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]
性能比较
在这里,我正在比较此处提到的所有答案的效果。不出所料,Arkku的 set
运营速度最快。
Arkku的设置差异 -第一次(每个循环0.124 微秒)
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.124 usec per loop
带有set
查找的Daniel Pryden的列表理解 -第二(每个循环0.302 微秒)
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.302 usec per loop
普通列表上的甜甜圈列表理解 -第三(每个循环0.552微秒)
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.552 usec per loop
Moinuddin Quadri的使用filter
-第四(每个循环0.972微秒)
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.972 usec per loop
Akshay Hazari's组合使用reduce
+filter
-第五(每个循环3.97usec)
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: 3.97 usec per loop
PS: set
不维持顺序,并从列表中删除重复的元素。因此,如果您需要使用任何设置差异,请不要使用。
在此处扩展Donut的答案和其他答案,通过使用生成器理解而不是列表理解,以及通过使用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)
结果将是可迭代的,将延迟获取已过滤列表。如果您需要一个真实的列表对象(例如,如果需要对len()
结果进行操作),则可以轻松构建一个列表,如下所示:
filtered_list = list(filter_list(full_list, excludes))
使用Python设置类型。那将是最Python的。:)
另外,由于它是本机的,因此它也应该是最优化的方法。
看到:
http://docs.python.org/library/stdtypes.html#set
http://docs.python.org/library/sets.htm(适用于较旧的python)
# Using Python 2.7 set literal format.
# Otherwise, use: l1 = set([1,2,6,8])
#
l1 = {1,2,6,8}
l2 = {2,3,5,8}
l3 = l1 - l2
l1
包含重复的元素,则此方法将不起作用。
使用 Set Comprehensions {x in l2中的x}或set(l2)进行设置,然后使用List Comprehensions获取列表
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
l2set = set( l2 )
而不是l2set = { x for x in l2 }
替代解决方案:
reduce(lambda x,y : filter(lambda z: z!=y,x) ,[2,3,5,8],[1,2,6,8])