History-Dependent List-Comprehension 或如何表达 `[f(x, this) for x in X if g(x, this)]`?
History-Dependent List-Comprehension or how to express `[f(x, this) for x in X if g(x, this)]`?
Python 的列表推导非常有用,因为它们允许我们将常见的模式写入简单、简洁、可读性极强的单行代码中:
带过滤器的循环
带中断的循环
l = []
<b>for</b> x <b>in</b> xs:
<b>if</b> g(x):
l.append(f(x))
l = []
<b>for</b> x <b>in</b> xs:
<b>if</b> <b>not</b> g(x):
<b>break</b>
l.append(f(x))
[f(x) <b>for</b> x <b>in</b> xs <b>if</b> g(x)]
[f(x) <b>for</b> x <b>in</b> takewhile(g, x)]
考虑允许 filter/break 依赖于所有先前生成的元素的稍微更通用的模式:
使用依赖于历史的过滤器循环
循环与历史相关的中断
l = []
<b>for</b> x <b>in</b> xs:
<b>if</b> g(x, l):
l.append(f(x))
l = []
<b>for</b> x <b>in</b> xs:
<b>if</b> <b>not</b> g(x, l):
<b>break</b>
l.append(f(x))
Question: Is it at all possible to translate these patterns into list-comprehensions as well?
对我来说,答案似乎是否定的/它只适用于 g
的非常特殊的情况(比如 ),因为其中一个需要能够引用列表创建时。
问题结束//有些语无伦次:
似乎需要一种全新的语法,类似于
[f(x) <b>for</b> x <b>in</b> xs <b>if</b> g(x, <b>这个</b>)]
其中 <b>this</b>
是新关键字的符号占位符,可以从上下文中引用外部对象。我不知道这在原则上是否完全可行,但能够编写
会很酷
使用依赖于历史的过滤器循环
循环与历史相关的中断
l = []
<b>for</b> x <b>in</b> xs:
<b>if</b> g(x, l):
l.append(f(x))
l = []
<b>for</b> x <b>in</b> xs:
<b>if</b> <b>not</b> g(x, l):
<b>break</b>
l.append(f(x))
[f(x) <b>for</b> x <b>in</b> xs <b>if</b> g(x, <b>这个</b>)]
[f(x) <b>for</b> x <b>in</b> xs <b>while</b> g(x, <b>这个</b>)]
或者更一般的
使用依赖于历史的过滤器和产量循环
具有依赖于历史的中断和收益的循环
l = []
<b>for</b> x <b>in</b> xs:
<b>if</b> g(x, l):
l.append(f(x, l))
l = []
<b>for</b> x <b>in</b> xs:
<b>if</b> <b>not</b> g(x, l):
<b>break</b>
l.append(f(x, l))
[f(x, <b>this</b>) <b>for</b> x <b>in</b> xs <b>if</b> g(x, <b>this</b>)]
[f(x, <b>this</b>) <b>for</b> x <b>in</b> xs <b>while</b> g(x, <b>this</b>)]
其中下一个元素和列表理解的退出条件都允许依赖于所有 先前生成的元素。在 set-builder notation 中,这两个结构将转换为
S⁽ⁿ⁺¹⁾ = { f(xₖ, S⁽ᵏ⁾) ∣ xₖ∈{x₁,…,xₙ} ∧ g(xₖ, S⁽ᵏ⁾) }
= S⁽ⁿ⁾ ∪ {f(xₙ, S⁽ⁿ⁾) ∣ g(xₙ, S⁽ⁿ⁾)}
和
S⁽ⁿ⁺¹⁾ = { f(xₖ, S⁽ᵏ⁾) ∣ xₖ∈{x₁,…,xₙ} ∧ ∀l≤k g(xₗ, S⁽ˡ⁾) }
= S⁽ⁿ⁾ ∪ {f(xₙ, S⁽ⁿ⁾) ∣ ∀k≤n g(xₖ, S⁽ᵏ⁾)}
是否有任何语言具有这样的功能?
可以通过使函数 f
and/or g
有状态(通常您希望将状态封装在某些 class).例如,这是一个列表理解,它贪婪地构建原始列表的升序子序列:
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, 1, 4, 1, 5, 1, 6]
state = State()
print([x for x in nums if state.is_ascending(x)])
# [1, 2, 3, 4, 5, 6]
在最坏的情况下,状态存储到目前为止添加的所有元素,这与 for
循环相比是多余的,但尽管如此,答案是您可以将其写成列表理解。
作为替代方案,您可以这样做:
result = []
result.extend(len(result) for i in range(10) if 5 not in result)
print(result)
# [0, 1, 2, 3, 4, 5]
请注意,extend
必须使用延迟计算的生成器表达式来调用,以便它生成的每个元素都可以添加到 result
(因此 result
将具有生成下一个元素之前的正确状态)。我不认为这是编写代码的好方法(而且它似乎取决于 extend
的未记录行为),但它确实实现了你正在尝试做的事情。
Python 的列表推导非常有用,因为它们允许我们将常见的模式写入简单、简洁、可读性极强的单行代码中:
带过滤器的循环 | 带中断的循环 |
---|---|
l = [] <b>for</b> x <b>in</b> xs: <b>if</b> g(x): l.append(f(x)) |
l = [] <b>for</b> x <b>in</b> xs: <b>if</b> <b>not</b> g(x): <b>break</b> l.append(f(x)) |
[f(x) <b>for</b> x <b>in</b> xs <b>if</b> g(x)] |
[f(x) <b>for</b> x <b>in</b> takewhile(g, x)] |
考虑允许 filter/break 依赖于所有先前生成的元素的稍微更通用的模式:
使用依赖于历史的过滤器循环 | 循环与历史相关的中断 |
---|---|
l = [] <b>for</b> x <b>in</b> xs: <b>if</b> g(x, l): l.append(f(x)) |
l = [] <b>for</b> x <b>in</b> xs: <b>if</b> <b>not</b> g(x, l): <b>break</b> l.append(f(x)) |
Question: Is it at all possible to translate these patterns into list-comprehensions as well?
对我来说,答案似乎是否定的/它只适用于 g
的非常特殊的情况(比如
问题结束//有些语无伦次:
似乎需要一种全新的语法,类似于
[f(x) <b>for</b> x <b>in</b> xs <b>if</b> g(x, <b>这个</b>)]
其中 <b>this</b>
是新关键字的符号占位符,可以从上下文中引用外部对象。我不知道这在原则上是否完全可行,但能够编写
使用依赖于历史的过滤器循环 | 循环与历史相关的中断 |
---|---|
l = [] <b>for</b> x <b>in</b> xs: <b>if</b> g(x, l): l.append(f(x)) |
l = [] <b>for</b> x <b>in</b> xs: <b>if</b> <b>not</b> g(x, l): <b>break</b> l.append(f(x)) |
[f(x) <b>for</b> x <b>in</b> xs <b>if</b> g(x, <b>这个</b>)] |
[f(x) <b>for</b> x <b>in</b> xs <b>while</b> g(x, <b>这个</b>)] |
或者更一般的
使用依赖于历史的过滤器和产量循环 | 具有依赖于历史的中断和收益的循环 |
---|---|
l = [] <b>for</b> x <b>in</b> xs: <b>if</b> g(x, l): l.append(f(x, l)) |
l = [] <b>for</b> x <b>in</b> xs: <b>if</b> <b>not</b> g(x, l): <b>break</b> l.append(f(x, l)) |
[f(x, <b>this</b>) <b>for</b> x <b>in</b> xs <b>if</b> g(x, <b>this</b>)] |
[f(x, <b>this</b>) <b>for</b> x <b>in</b> xs <b>while</b> g(x, <b>this</b>)] |
其中下一个元素和列表理解的退出条件都允许依赖于所有 先前生成的元素。在 set-builder notation 中,这两个结构将转换为
S⁽ⁿ⁺¹⁾ = { f(xₖ, S⁽ᵏ⁾) ∣ xₖ∈{x₁,…,xₙ} ∧ g(xₖ, S⁽ᵏ⁾) }
= S⁽ⁿ⁾ ∪ {f(xₙ, S⁽ⁿ⁾) ∣ g(xₙ, S⁽ⁿ⁾)}
和
S⁽ⁿ⁺¹⁾ = { f(xₖ, S⁽ᵏ⁾) ∣ xₖ∈{x₁,…,xₙ} ∧ ∀l≤k g(xₗ, S⁽ˡ⁾) }
= S⁽ⁿ⁾ ∪ {f(xₙ, S⁽ⁿ⁾) ∣ ∀k≤n g(xₖ, S⁽ᵏ⁾)}
是否有任何语言具有这样的功能?
可以通过使函数 f
and/or g
有状态(通常您希望将状态封装在某些 class).例如,这是一个列表理解,它贪婪地构建原始列表的升序子序列:
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, 1, 4, 1, 5, 1, 6]
state = State()
print([x for x in nums if state.is_ascending(x)])
# [1, 2, 3, 4, 5, 6]
在最坏的情况下,状态存储到目前为止添加的所有元素,这与 for
循环相比是多余的,但尽管如此,答案是您可以将其写成列表理解。
作为替代方案,您可以这样做:
result = []
result.extend(len(result) for i in range(10) if 5 not in result)
print(result)
# [0, 1, 2, 3, 4, 5]
请注意,extend
必须使用延迟计算的生成器表达式来调用,以便它生成的每个元素都可以添加到 result
(因此 result
将具有生成下一个元素之前的正确状态)。我不认为这是编写代码的好方法(而且它似乎取决于 extend
的未记录行为),但它确实实现了你正在尝试做的事情。