当前位置: 首页 > 面试题库 >

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

公羊信厚
2023-03-14
问题内容

我有一个列表理解,近似为:

[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)]

对于这种更复杂的情况,我认为备忘录可以产生更干净的最终结果。


问题答案:

一种解决方案(最好是如果您重复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的计算成本,原始列表中的重复次数和处置时的内存,您需要权衡选择。记忆化在空间速度上进行了折衷,这意味着它会跟踪保存每个结果的方式,因此,如果您有大量列表,则在内存占用方面可能会变得代价高昂。



 类似资料:
  • 问题内容: 这是我在处理Django项目时出现的一个问题。关于表单验证。 在Django中,当您提交表单时,可以调用相应的表单对象以触发验证并返回布尔值。因此,通常在视图函数中有类似的代码: 不仅可以验证表单数据,还可以向表单对象添加错误消息,这些错误消息随后可以显示给用户。 在一页上,我同时使用两种形式,并且还希望仅当两种形式均包含有效数据时才保存数据。这意味着我必须在执行代码以保存数据之前在两

  • 我有一个非常简单的表,有3列,我需要一个尽可能轻量级的查询,只有当列有新值时才能插入。 如何编写sql查询来实现这一点?我在网站上已经看到了一些例子,但它们都被我无法理解的更复杂的查询(一些涉及子查询)所混淆。 似乎有不同的方法来做这件事,我需要找到最轻量级的一个,这样我就可以在循环中重复它,一次插入多个标签,而不会给服务器带来太大的压力。

  • 问题内容: 我是mongodb的新手。我可以知道如何避免重复输入。在关系表中,我们使用主键来避免它。我可以知道如何使用Java在Mongodb中指定它吗? 问题答案: 在选项中使用索引。 您也可以跨多个字段执行此操作。 有关 更多详细信息和示例, 请参阅 文档中的 此部分 。 MongoDB索引可以有选择地施加一个 唯一的键约束 ,以确保不会插入任何索引键值与现有文档值匹配的文档。 如果希望从唯一

  • 问题内容: 我对SQL完全陌生,但是可以说,在StackExchange Data Explorer上 ,我只想按信誉列出前15位用户,并且我写了这样的内容: 我认为,这目前是有意义的,因为不是中的列。我可以轻松地说出这个问题,基本上是在重复公式。 因此,问题是: 我可以在条款中实际使用“列”吗? 我是否可能需要使用此列创建一个虚拟表/视图,然后对其进行查询? 我可以命名一个表达式吗,例如,所以我

  • 问题内容: 我正在尝试在两个数据帧之间合并。每个数据帧都有两个索引级别(日期,客户)。在列中,例如,某些列在两者之间匹配(货币,日期)。 按索引合并这些内容的最佳方法是什么,但不要采用两个副本的货币和日期。 每个数据框都是90列,所以我试图避免用手将所有内容写出来。 如果我做: 我懂了 谢谢!… 问题答案: 您可以算出仅在一个DataFrame中的列,并使用它来选择合并中列的子集。 然后执行合并(

  • 我使用for循环将学生详细信息添加到ArrayList。当我给第二个学生提供详细信息时,它会覆盖第一个数据。螺柱类 将数据添加到ArrayList的主类。 输出:第二个数据[2,2]后的实际输出辊数[1]。预期输出应为卷号: A1姓名: F1 L1性别:男性年龄: 11体育赛事:标枪 报名号:A2姓名:F2 L2性别:女年龄:14体育项目:100米跑 报名号:A3姓名:F3 L3性别:男性年龄:1