Python 如何筛选出两个巨大列表的列表项?
我有一个巨大的列表,它是Python 如何筛选出两个巨大列表的列表项?,python,performance,Python,Performance,我有一个巨大的列表,它是所有\u条目(目前为80k个整数项)。此列表中包含我在整个程序中已处理的项目 当我的程序使用以下方法时,通常需要30秒左右才能到达return语句。我怎样才能加快速度 提示:new_条目有40k长,而且非常大 def get_fresh_entries(self, new_entries, all_entries): """ :param new_entries: Entries from which some might already be in al
所有\u条目
(目前为80k个整数项)。此列表中包含我在整个程序中已处理的项目
当我的程序使用以下方法时,通常需要30秒左右才能到达return语句。我怎样才能加快速度
提示:new_条目
有40k长,而且非常大
def get_fresh_entries(self, new_entries, all_entries):
"""
:param new_entries: Entries from which some might already be in all_entries.
:param all_entries: Entries already handled and saved.
"""
fresh = []
shuffle(new_entries)
for i in new_entries:
if i not in all_entries:
fresh.append(i)
if len(fresh) > 80000:
break
return fresh
一份清单可以: 作为@Delgan注释,如果所有_条目都是一个集合,则注释效果更好
all_entries = set(all_entries)
然后:
再看看,它是:
如果您只需要保留第一个n
数据,因为itertools是惰性的,您可以这样处理它们:
fresh = itertools.islice(itertools.ifilter(lambda x: x not in all_entries,
new_entries),
n))
或者使用类似的列表,但使用生成器:
fresh = itertools.islice((x for x in new_entries if x not in all_entries), n)
使用set操作可以显著加快代码的速度。我定义了一个新函数
get_fresh_entries_2
,它使用set操作。最后,我添加了一个小的速度比较。使用set操作可以大大加快进程
from random import shuffle
from itertools import compress
from time import time
def get_fresh_entries_2(new_entries, all_entries):
shuffle(new_entries)
diff = set(new_entries)- set(all_entries)
if len(new_entries) > 80000:
ind = [i in diff for i in new_entries[:80000]]
else:
ind = [i in diff for i in new_entries]
fresh = compress(new_entries,ind)
return list(fresh)
def get_fresh_entries(new_entries, all_entries):
"""
:param new_entries: Entries from which some might already be in all_entries.
:param all_entries: Entries already handled and saved.
"""
fresh = []
shuffle(new_entries)
for i in new_entries:
if i not in all_entries:
fresh.append(i)
if len(fresh) > 80000:
break
return fresh
new_entries = np.asarray(np.random.randint(1,11, size = (40000))).tolist()
all_entries = np.asarray(np.random.randint(0,10, size = (80000))).tolist()
t0 = time()
a = get_fresh_entries(new_entries, all_entries)
t1 = time()
b = get_fresh_entries_2(new_entries, all_entries)
t2 = time()
t1-t0 # 4.321316957473755 sec
t2-t1 # 0.005052804946899414 sec
唯一的问题是行
如果不是在所有的_条目中:
,它对每个新条目执行,并对多达80k个现有条目进行测试
在这里,在列表或集合上执行测试时,了解差异非常重要
- 测试一个元素是否在列表中,就像测试某人是否在家而不知道地址(仅知道城镇)并且挨家挨户
- 测试一个元素是否在集合中就像测试某人是否在家,知道确切的地址并按一个门铃
所有_条目
转换为一个集合(!)即可消除主要的速度问题
...
all_entries_set = set(all_entries)
for i in new_entries:
if i not in all_entries_set:
...
虽然还有其他一些提示,但是如何使用集合来加速程序是关键的,因为它可以降低复杂性。40k和80k不是很大的
[x对于x在新的\u条目中,如果x不是在所有的\u条目中]
是吗?而且所有的\u条目都应该是set()
所以x不在所有的\u条目中
是O(1)
。您可以使用生成器来代替列表理解。好的,这似乎在某种程度上是可行的,但我实际上只是使用循环。使用列表理解或生成器并不能解决OP的问题,但只会使其变得更加复杂。创建所有的条目集合是唯一重要的部分,你甚至没有强调这一点。@tobias_k,也许循环在某种程度上更全面,可能也慢得多,itertools用于此类操作,但这只是个人的一种欣赏,对你和我来说,继续回答并扩展这个问题,这样当有人对同样的问题表示怀疑时,用户就有了广泛的选择。谢谢!!:)itertools.islice((如果x不是在所有的\u条目中,则x代表x),80000)
@Saphire,如果您去掉shuffle(new\u条目)
步骤,实现速度会更快(以9-10的顺序)True如果条件else False
与condition
相同。另外,为什么要将diff
转换为列表
?这只会使查找速度变慢。@tobias_k编辑了答案。该操作确实加快了[如果新的\u条目中的i存在差异[:80000],则为True]
语法错误;它应该只是[i in diff for i in new_entries[:80000]]
。此外,无论列表中的条目是否超过80k,您都可以在这两种情况下使用它。此外,这些函数也不是等价的。过滤前限制为80k将使结果少于80k。
from random import shuffle
from itertools import compress
from time import time
def get_fresh_entries_2(new_entries, all_entries):
shuffle(new_entries)
diff = set(new_entries)- set(all_entries)
if len(new_entries) > 80000:
ind = [i in diff for i in new_entries[:80000]]
else:
ind = [i in diff for i in new_entries]
fresh = compress(new_entries,ind)
return list(fresh)
def get_fresh_entries(new_entries, all_entries):
"""
:param new_entries: Entries from which some might already be in all_entries.
:param all_entries: Entries already handled and saved.
"""
fresh = []
shuffle(new_entries)
for i in new_entries:
if i not in all_entries:
fresh.append(i)
if len(fresh) > 80000:
break
return fresh
new_entries = np.asarray(np.random.randint(1,11, size = (40000))).tolist()
all_entries = np.asarray(np.random.randint(0,10, size = (80000))).tolist()
t0 = time()
a = get_fresh_entries(new_entries, all_entries)
t1 = time()
b = get_fresh_entries_2(new_entries, all_entries)
t2 = time()
t1-t0 # 4.321316957473755 sec
t2-t1 # 0.005052804946899414 sec
...
all_entries_set = set(all_entries)
for i in new_entries:
if i not in all_entries_set:
...