历史相关列表理解或如何表达`[f(x, this) for x in X if g(x, this)]`?

问题描述

Python 的列表推导式非常有用,因为它们允许我们将常见模式写入简单、简洁、非常易读的单行代码

带过滤器的循环 带中断循环
l = []
for x in xs:
if g(x):
l.append(f(x))
l = []
for x in xs:
if not g(x):
break
l.append(f(x))
[f(x) for x in xs if g(x)] [f(x) for x in takewhile(g,x)]

考虑允许过滤器/中断依赖于所有先前生成的元素的稍微更一般的模式:

具有历史依赖过滤器的循环 具有历史依赖中断的循环
l = []
for x in xs:
if g(x,l):
l.append(f(x))
l = []
for x in xs:
if not g(x,l):
break
l.append(f(x))

问题:是否有可能将这些模式也转化为列表推导式?

对我来说,答案似乎是否定的/它仅适用于非常特殊的 g(例如 [1]),因为在一个情况下需要能够引用列表正在创建中。




问题结束 // 一些不连贯的漫谈:

似乎需要一种全新的语法

[f(x) for x in xs if g(x,this)]

其中 this 是新关键字的符号占位符,用于从上下文中引用外部对象。我不知道这在原则上是否可行,但是能够编写会很酷

具有历史依赖过滤器的循环 具有历史依赖中断的循环
l = []
for x in xs:
if g(x,l):
break
l.append(f(x))
[f(x) for x in xs if g(x,this)] [f(x) for x in xs while g(x,this)]

或者更一般的

具有历史相关过滤器和产量的循环 具有与历史相关的中断和产量的循环
l = []
for x in xs:
if g(x,l):
l.append(f(x,l))
l = []
for x in xs:
if not g(x,l):
break
l.append(f(x,l))
[f(x,this) for x in xs if g(x,this)] [f(x,this) for x in xs while g(x,this)]

允许列表推导式的下一个元素和退出条件依赖于所有先前生成的元素。在 set-builder notation 中,这两个构造将转换为

S⁽ⁿ⁺¹⁾ = { f(xₖ,S⁽ᵏ⁾) ∣ xₖ∈{x₁,…,xₙ} ∧ g(xₖ,S⁽ᵏ⁾) } 
       = S⁽ⁿ⁾ ∪ {f(xₙ,S⁽ⁿ⁾) ∣ g(xₙ,S⁽ⁿ⁾)}

S⁽ⁿ⁺¹⁾ = { f(xₖ,xₙ} ∧ ∀l≤k g(xₗ,S⁽ˡ⁾) } 
       = S⁽ⁿ⁾ ∪ {f(xₙ,S⁽ⁿ⁾) ∣ ∀k≤n g(xₖ,S⁽ᵏ⁾)}

是否有任何语言具有这样的功能

解决方法

通过使函数 f 和/或 g 有状态(通常您希望将状态封装在某个类的实例中),可以将它们转换为列表推导式。例如,这是一个列表推导式,它贪婪地构建原始列表的升序子序列:

class State:
    def __init__(self):
        self.x = None
    def is_ascending(self,x):
        if self.x is None or x > self.x:
            self.x = x
            return True
        else:
            return False

nums = [1,2,1,3,4,5,6]
state = State()

print([x for x in nums if state.is_ascending(x)])
# [1,6]

在最坏的情况下,状态存储到目前为止添加的所有元素,这与 for 循环相比是多余的,但答案是您可以将其编写为列表推导式。


作为替代,您可以执行以下操作:

result = []
result.extend(len(result) for i in range(10) if 5 not in result)
print(result)
# [0,5]

请注意,extend 必须使用延迟计算的生成器表达式调用,以便它生成的每个元素都可以添加到 result(因此 result 将具有正确的状态在生成下一个元素之前)。我不认为这是编写代码的好方法(它似乎取决于 extend 的未记录行为),但它确实实现了您想要做的事情。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...