Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/340.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何筛选出两个巨大列表的列表项?_Python_Performance - Fatal编程技术网

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:
        ...