我有大量的2个列表,我希望将彼此的元素排除在外。
做普通
会更快吗?[x for x in list1 if x not in list2]
或者我应该以另一种格式(set
,dictionary
使用键类型=无,hashMap
)转换list1和/或list2,还是使用一些预先实现的包函数?
感谢。
修改 订单无关紧要。
答案 0 :(得分:4)
这是你的慢速方法:
[x for x in list1 if x not in list2] #O(n*m)
这是一个EVEN SLOWER方法:
[x for x in list1 if x not in set(list2)] #O(n*m) with extra overhead
这是一种快速方法:
s = set(list2) #O(m)
[x for x in list1 if x not in s] #O(n)
x in list2
是O(n)操作。 set(list2)
中的x对于in
部分是O(1),而对于集合构建部分是O(n)。第二种方法更慢的原因是它为每个成员资格测试构建了一个新的set
,而不是只构建一次并对其进行查找。
答案 1 :(得分:1)
其他人已经打败了我的Python内存解决方案,但我想补充说,这似乎是治疗症状而不是治愈疾病的情况。为什么首先列出内存大的列表?
显然我不知道应用程序的性质,但考虑使用数据库,运行后台批处理作业和缓存结果等替代方案,尝试用更好的设计解决这个问题。
答案 2 :(得分:1)
如果您可以使用套装,则不会重复项目:
a = set(list1)
b = set(list2)
c = a.difference(b)
答案 3 :(得分:1)
我会选择设置解决方案,控制台中的快速微基准可能看起来像这样(我个人不会担心设置构造开销,除非经常执行):
list1 = range(50000)
list2 = range(10000, 20000)
%timeit [x for x in list1 if x not in list2]
# 8.48 s per loop
slist2 = set(list2)
%timeit [x for x in list1 if x not in slist2]
# 3.62 ms per loop
答案 4 :(得分:1)
这是一种破坏原始订单的方法,但可能更快,“取决于”。它依赖于elements()
对象鲜为人知的collections.Counter
方法:
from collections import Counter
xs = ["abc", "def", "abc", "abc", "def", "def", "xyz"]
ys = ["def", "def", "jik"]
xsc = Counter(xs)
for y in set(ys): # if y has few repeated elements, skip `set()`
xsc[y] = 0
print list(xsc.elements())
打印(可能 - 订单未定义!):
['xyz', 'abc', 'abc', 'abc']
答案 5 :(得分:0)
加速的唯一方法是对list2
中的成员资格进行测试,因此请尝试
[ x for x in list1 if x not in set(list2) ]
这是否更快取决于对集合执行len(list1)
操作所节省的时间是否弥补了构建集合所需的时间,这取决于两个列表的长度。