数组/列表中的第0个空元素,用于消除重复递减。这会改善性能吗?

时间:2013-09-22 20:17:55

标签: python arrays performance

我使用Python来解决Project Euler问题。许多人需要缓存过去计算的结果以提高性能,从而产生如下代码:

pastResults = [None] * 1000000
def someCalculation(integerArgument):
    # return result of a calculation performed on numberArgument
    # for example, summing the factorial or square of its digits
for eachNumber in range(1, 1000001)
    if pastResults[eachNumber - 1] is None:
        pastResults[eachNumber - 1] = someCalculation(eachNumber)
        # perform additional actions with pastResults[eachNumber - 1]

重复递减是否会对计划绩效产生负面影响?是否有一个空的或虚拟的第零个元素(所以基于零的数组模拟一个基于数组的数组)通过消除重复的递减来提高性能?

pastResults = [None] * 1000001
def someCalculation(integerArgument):
    # return result of a calculation performed on numberArgument
    # for example, summing the factorial or square of its digits
for eachNumber in range(1, 1000001)
    if pastResults[eachNumber] is None:
        pastResults[eachNumber] = someCalculation(eachNumber)
        # perform additional actions with pastResults[eachNumber]

我还觉得模拟一个基于数组的数组会使代码更容易理解。这就是为什么我不会将for eachNumber in range(1000000)作为范围从零开始,因为someCalculation(eachNumber + 1)不合逻辑。

空的第0个元素的附加内存有多重要?我还应该考虑哪些其他因素?我更喜欢那些不仅限于Python和Project Euler的答案。

编辑:应该是is None而不是is not None

1 个答案:

答案 0 :(得分:3)

不是关于性能问题的答案,而是关于缓存先前计算值的一般提示。通常的方法是使用映射(Python dict),因为这允许使用更复杂的键而不是整数,如浮点数,字符串甚至元组。此外,如果您的密钥相当稀疏,您也不会遇到问题。

pastResults = {}
def someCalculation(integerArgument):
    if integerArgument not in pastResults:
        pastResults[integerArgument] = # calculation performed on numberArg.
    return pastResults[integerArgument]

此外,无需使用循环“按顺序”执行计算。只需为你感兴趣的值调用函数,if语句就会注意,当递归调用时,每个参数只调用一次函数。

最终,如果你经常使用它(就像Project Euler的情况那样),你可以自己定义function decorator,就像这样:

def memo(f):
    f.cache = {}
    def _f(*args, **kwargs):
        if args not in f.cache:
            f.cache[args] = f(*args, **kwargs)
        return f.cache[args]
    return _f

它的作用是:它接受一个函数并定义另一个函数,它首先检查是否可以在缓存中找到给定的参数,否则计算原始函数的结果并将其放入缓存中。只需将@memo注释添加到函数定义中,这将为您处理缓存。

@memo
def someCalculation(integerArgument):
    # function body

这是someCalculation = memo(someCalculation)的语法糖。但请注意,这并不总是很好。首先,paremters必须是可清洗的(没有列表或其他可变类型);第二,如果您传递的参数与结果无关(例如,调试内容等),您的缓存可能会不必要地变大,因为 all 将参数用作密钥。