计算两个不同列表元素之间重函数的最快方法

Fastest way to calculate a heavy function between elements of two different lists

正如标题中所写,我想知道是否有比我发现的方法更快的方法来在两个列表的元素之间执行计算复杂的函数。

这里我将以阶乘为例,但该函数是一个发电机函数,用于检查两个元素之间是否存在交集。

这就是我到目前为止能够做到的。谁能帮帮我?

%%time
import random
import itertools
import math
random.seed(10)

list1=[random.randint(1, 100) for i in range(10000)]
list2=[random.randint(1, 10) for i in range(100)]

two_lists=[list1,list2]
permutation = itertools.product(*two_lists) # I obtain the permutation ty Cyttorak
result=[math.factorial(x[0]+x[1]) for x in permutation] # The complex operation (factorial of the sum)
Wall time: 1.11 s

这将重复做同样的工作,因为您经常从非常小的池中挑选。您可以缓存结果,例如使用 dict:

list1=[random.randint(1, 100) for i in range(10000)]
list2=[random.randint(1, 10) for i in range(100)]

cache = {}

result=[cache.get(s, factorial(s)) for s in map(sum, product(list1, list2))]

我只能通过摆脱索引、冗余列表和缓存计算来获得 8 倍的速度。 maxsize 已为您的示例量身定制。

from functools import lru_cache

@lru_cache(maxsize=128)
def facto(x):
    return math.factorial(x)

result=[facto(x+y) for x,y in itertools.product(list1, list2)]

在最初的问题中,创建了一个阶乘列表(结果),尽管它显然没有被使用。此代码与该异常一致,通常在我的机器上执行 ~0.11s :-

import random
from math import factorial
from itertools import product
import time
from functools import lru_cache


@lru_cache(maxsize=110)
def facto(n):
    return factorial(n)


start = time.perf_counter()
list1 = [random.randint(1, 100) for i in range(10000)]
list2 = [random.randint(1, 10) for i in range(100)]
result = [facto(x) for x in map(sum, product(list1, list2))]
end = time.perf_counter()
print(end-start)

感谢 Michael Szczesny 提出使用 lru_cache

的想法

如果函数计算复杂,优化构造列表元素组合的循环是浪费时间。只要确保

(a) 每个不同的元素组合只计算一次,并且

(b) 如果函数适用于递归计算,重新实现计算以节省时间(例如,对于阶乘,您可以缓存较小的值并将它们用于较大的数字。)