Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/list/4.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_List_Algorithm_Performance_List Comprehension - Fatal编程技术网

Python 优化复杂列表理解语句

Python 优化复杂列表理解语句,python,list,algorithm,performance,list-comprehension,Python,List,Algorithm,Performance,List Comprehension,如何优化第3步中的列表理解语句? 背景: 在现实世界中: r包含约500个元素和 a包含约100万个元素 请注意,步骤3是r和a上的嵌套循环。因此,这需要很多时间。在下面的代码中,为了简单起见,缩短了r和a 出于背景目的,我还提到了这个函数,some\u-heavy\u-calculation()。这个函数在这里没有显示,但由于它也被称为len(r)*len(a)次,因此它也会消耗大量时间 为了加快速度,我注意到,通过引入“更快”选项,我可以避免90-95%的调用一些较重的计算()。唯一的问

如何优化
第3步中的列表理解语句?

背景:

在现实世界中:

  • r
    包含约500个元素和
  • a
    包含约100万个元素
请注意,
步骤3
r
a
上的嵌套循环。因此,这需要很多时间。在下面的代码中,为了简单起见,缩短了
r
a

出于背景目的,我还提到了这个函数,
some\u-heavy\u-calculation()
。这个函数在这里没有显示,但由于它也被称为
len(r)*len(a)
次,因此它也会消耗大量时间

为了加快速度,我注意到,通过引入“更快”选项,我可以避免90-95%的调用
一些较重的计算()
。唯一的问题是
步骤3
现在需要很多时间。事实上,这一步耗费的时间比我所能节省的要多

def some_heavy_calculation(rules, data) -> list:
    # ...
    return []

# r = input rules
r =  ['x', 'y', 'z']

# a = input data
a =  [7,     7,     7,     4,     4,     2,     2,     8,     2,     9,     4,     4,     8,     7    ]

#########
# Slow alternative: b = result of some_heavy_calculation(r, a)
# b = expected result, size: [ r x a ]
b = [[True,  True,  True,  True,  True,  True,  True,  True,  True,  False, True,  True,  True,  True],
     [True,  True,  True,  False, False, True,  True,  True,  True,  False, False, False, True,  True],
     [False, False, False, True,  True,  False, False, True,  False, False, True,  True,  True,  False]]
#########

#########
# Faster:
# Since these steps avoids 90-95 % of all the calls to some_heavy_calculation()
#
# Step 1: c = a in order, but without duplicates
c =  [7,                   4,            2,            8,            9                                ] 

# Step 2: d = result of calculation, size: [ r x c ]
d = [[True,                True,         True,         True,         False                            ],
     [True,                False,        True,         True,         False                            ],
     [False,               True,         False,        True,         False                            ]]

# Step 3: e = should equal b
e = [[d[ri][next(ci for ci, cv in enumerate(c) if cv == av)] for ai, av in enumerate(a)] for ri, rv in enumerate(r)]
#########

str(b) == str(e) # <--- returns True
def一些繁重的计算(规则、数据)->列表:
# ...
返回[]
#r=输入规则
r=['x','y','z']
#a=输入数据
a=[7,7,7,4,4,2,2,8,2,9,4,4,8,7]
#########
#慢备选方案:b=一些重计算的结果(r,a)
#b=预期结果,大小:[r x a]
b=[[真,真,真,真,真,真,真,真,假,真,真,真,真,真],
[真,真,真,假,假,真,真,真,真,假,假,假,假,真,真],
[假,假,假,真,真,假,假,真,假,假,真,真,真,真,假]]
#########
#########
#更快:
#因为这些步骤避免了90-95%的对某些计算()的调用
#
#步骤1:c=a按顺序排列,但无重复项
c=[7,4,2,8,9]
#步骤2:d=计算结果,尺寸:[r x c]
d=[[True,True,True,True,False],
[真,假,真,真,假],
[假,真,假,真,假]]
#步骤3:e=应等于b
e=[[d[ri][next(ci代表ci,cv代表枚举(c)中的cv,如果cv==av)]代表ai,av代表枚举(a)]代表ri,rv代表枚举(r)]
#########

str(b)==str(e)#在我看来,您需要的是一个名为

有一个decorator(对于Python<3.9,您可以使用)可以这样使用:

import functools

@functools.cache
def some_heavy_calculation_per_item(rules, value) -> bool:
    # ...
    return []

def some_heavy_calculation(rules, data) -> list:
    # ...
    returned = []
    for value in data:
        returned.append(some_heavy_calculation_per_item(rules, value))

    return returned
使用memorization可以有效地对每个值进行一次计算(如您所述,可以节省90-95%),但也可以采用内存高效的方式(无需组合许多大型列表或数组)


另一种可能的优化方法是使用
yield
而不是在
some\u-heavy\u-calculation
函数中构建列表,但这取决于您使用结果的方式-如果逐值计算,则
yield
ing将提高性能。如果你需要完整的列表,那么它将毫无帮助。

列表理解只是一种从
d
中查找与
r
a
元素相对应的元素的方法吗?是的,确切地说,只是不使用枚举(a)
中的
ai
值。美好的我一点也没听说过。即使并行地执行一些重的计算()也行吗。我使用的是Pool(processs=8)和Pool.map(partial(some_function,…),rules),其中some_function()反过来应用some_-heavy_计算()。是的,每个进程都应该构造一个单独的缓存,这样可能会有一些重复(在最坏的情况下,您必须检查它-每个进程分别初始化缓存函数)。。但是,您可以明智地将相同的值发送到相同的进程—只需将值发送到
id=number%8
%
为模)的进程即可—缓存的使用将非常有效,并且只需计算一次结果。