Python列表理解 - 避免重复评估

2024-05-29 04:42:00 发布

您现在位置:Python中文网/ 问答频道 /正文

我对清单的理解大致如下:

[f(x) for x in l if f(x)]

其中l是一个列表,f(x)是一个昂贵的函数,它返回一个列表。

我想避免每出现一个非空的f(x)就计算f(x)两次。有没有办法把它的输出保存在列表理解中?

我可以删除最后一个条件,生成整个列表,然后将其删减,但这似乎是浪费。

编辑

提出了两种基本方法:

一个内在的发电机理解:

[y for y in (f(x) for x in l) if y]

或者备忘录。

我认为内部生成器对于上述问题的理解是优雅的。事实上,我简化了这个问题,想说清楚,我真的想:

[g(x, f(x)) for x in l if f(x)]

对于这种更复杂的情况,我认为记忆产生了一个更清晰的最终结果。


Tags: 方法记忆函数in编辑列表forif
3条回答
[y for y in (f(x) for x in l) if y]

会的。

你应该用一个备忘录装饰器。这里有一个有趣的link


使用链接和“代码”中的备忘录:

def memoize(f):
    """ Memoization decorator for functions taking one or more arguments. """
    class memodict(dict):
        def __init__(self, f):
            self.f = f
        def __call__(self, *args):
            return self[args]
        def __missing__(self, key):
            ret = self[key] = self.f(*key)
            return ret
    return memodict(f)

@memoize
def f(x):
    # your code

[f(x) for x in l if f(x)]

一个解决方案(如果x值重复,最好是将函数f记住,即创建一个包装函数,保存调用函数的参数并保存它,而不是在要求相同的值时返回它。

一个非常简单的实现如下:

storage = {}
def memoized(value):
    if value not in storage:
        storage[value] = f(value)
    return storage[value]

[memoized(x) for x in l if memoized(x)]

然后在列表理解中使用这个函数。该方法在理论和实际两个条件下都是有效的。第一个是函数f应该是确定性的,即给定相同的输入返回相同的结果,第二个是对象x可以用作字典键。如果第一个方法无效,则应根据定义每次重新计算f,而如果第二个方法失败,则可以使用稍微更健壮的方法。

你可以在网络上找到很多回忆录的实现,我认为python的新版本也包含了一些东西。

另一方面,不要使用小的L作为变量名,这是一个坏习惯,因为在某些终端上,它可能会与i或1混淆。

编辑:

如前所述,使用生成器理解(以避免创建无用的重复临时对象)的一个可能的解决方案是:

[g(x, fx) for x, fx in ((x,f(x)) for x in l) if fx]

考虑到f的计算成本、原始列表中的重复次数和可配置的内存,您需要权衡您的选择。记忆录可以在空间速度上进行权衡,这意味着它会记录保存的每个结果,因此如果你有大量的列表,那么在内存占用方面可能会变得昂贵。

相关问题 更多 >

    热门问题