目前,您正在循环lst1
并lst2
一次生成uniq
. 然后您lst1
再次循环以生成uniq_full
.
相反,您可以循环lst2
一次以生成要删除的键,然后循环lst1
一次以过滤掉不需要的元素:
lst1 = [('vr1', '635', '1'), ('vr1', '32', '1'), ('vr1', '784', '0.526'), ('vr1', '431', '1')]
lst2 = [('vr1', '635', '3'), ('vr1', '784', '2.526'), ('vr1', '431', '2')]
remove_keys = set([item[:2] for item in lst2])
unique = [item for item in lst1 if item[:2] not in remove_keys]
print(unique)
产量
[('vr1', '32', '1')]
这是一个 timeit 测试(使用IPython),它表明它更快:
def orig(lst1, lst2):
uniq = set([i[0:2] for i in lst1]).difference([j[0:2] for j in lst2])
uniq_full = [i for i in lst1 if i[0:2] in uniq]
return uniq_full
def alt(lst1, lst2):
remove_keys = set([item[:2] for item in lst2])
unique = [item for item in lst1 if item[:2] not in remove_keys]
return unique
In [4]: %timeit orig(lst1, lst2)
100000 loops, best of 3: 2.29 µs per loop
In [5]: %timeit alt(lst1, lst2)
1000000 loops, best of 3: 1.36 µs per loop
关于@otus 的评论(下):让我们看看在创建时使用生成器表达式是否remove_keys
可以提高速度:
def alt2(lst1, lst2):
remove_keys = set(item[:2] for item in lst2)
unique = [item for item in lst1 if item[:2] not in remove_keys]
return unique
In [7]: %timeit alt2(lst1, lst2)
1000000 loops, best of 3: 1.54 µs per loop
以下是包含 ~10**4 个项目的列表的基准:
In [8]: lst1 = [('vr1', '635', '1'), ('vr1', '32', '1'), ('vr1', '784', '0.526'), ('vr1', '431', '1')]*10000
In [9]: lst2 = [('vr1', '635', '3'), ('vr1', '784', '2.526'), ('vr1', '431', '2')]*10000
In [10]: %timeit alt(lst1, lst2)
100 loops, best of 3: 9.34 ms per loop
In [11]: %timeit alt2(lst1, lst2)
100 loops, best of 3: 9.49 ms per loop
In [12]: %timeit orig(lst1, lst2)
100 loops, best of 3: 13.5 ms per loop
这是另一个包含 ~10**6 项的列表的基准:
In [19]: %timeit alt(lst1, lst2)
1 loops, best of 3: 972 ms per loop
In [20]: %timeit alt2(lst1, lst2)
1 loops, best of 3: 957 ms per loop
因此,对于中小型列表,列表理解更快,但对于较大的列表,使用生成器表达式更快。当然,什么被认为是大或小取决于您的机器。您需要使用timeit进行基准测试,以了解最适合您的方法。
通常,当您有足够的内存时,如果您需要遍历整个集合,使用列表推导式似乎比生成器更快。当您没有足够的内存或不需要遍历整个集合时,生成器会更好。
查看@thg435 的解决方案也很有趣。在某些情况下它更快:
def using_dicts(lst1, lst2):
d1 = {x[0:2]:x for x in lst1}
d2 = {x[0:2]:x for x in lst2}
return [d1[key] for key in set(d1) - set(d2)]
如果您的列表包含大量重复键:
lst1 = [('vr1', '635', '1'), ('vr1', '32', '1'), ('vr1', '784', '0.526'), ('vr1', '431', '1')]*10000
lst2 = [('vr1', '635', '3'), ('vr1', '784', '2.526'), ('vr1', '431', '2')]*10000
然后using_dicts
比alt
:
In [31]: %timeit alt(lst1, lst2)
100 loops, best of 3: 8.39 ms per loop
In [32]: %timeit using_dicts(lst1, lst2)
100 loops, best of 3: 7.98 ms per loop
我认为这是因为在上面的示例中,lst1
并且lst2
包含很多重复x[0:2]
的 sd1
并且d2
很小。
如果您的lst1
和lst2
包含许多唯一键,例如何时
lst1 = [(i,i,i) for i in range(10**4+100)]
lst2 = [(i,i,i) for i in range(10**4)]
然后alt
比using_dicts
:
In [34]: %timeit alt(lst1, lst2)
100 loops, best of 3: 3.12 ms per loop
In [35]: %timeit using_dicts(lst1, lst2)
100 loops, best of 3: 5.93 ms per loop