如何解决历史相关列表理解或如何表达`[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
的未记录行为),但它确实实现了您想要做的事情。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。