列表推导应该返回列表。如果你的 reduce 应该返回一个列表,那么是的,你可以用列表理解替换它。
但这并不是提供“类reduce 功能”的障碍。 Python 列表可以包含任何对象。如果您接受包含在单项列表中的结果,那么有一个 [...][0] 列表理解表单可以替换任何 reduce()。
这应该是显而易见的,但这种形式是
[x for x in [reduce(function, sequence, initial)]][0]
对于一些二进制 function 和一些可迭代的 sequence 和一些 initial 值。或者,如果您想要第一个可迭代对象中的 initial,
[x for x in [reduce(function, sequence)]][0]
可以说,以上内容是作弊,而且毫无意义,因为您可以在没有理解的情况下使用reduce。所以让我们在没有reduce 的情况下尝试一下。
[stack.append(function(stack.pop(), e)) or stack[0]
for stack in ([initial],)
for e in sequence][-1]
这会生成所有中间值的列表,我们想要最后一个。 [-1] 和 [0] 一样简单。我们需要一个累加器来减少,但不能在理解中使用赋值语句,因此stack(这只是一个列表),但我们可以在这里使用许多其他数据结构。 .append() 始终返回 None,因此我们使用 or stack[0] 将到目前为止的值放入结果列表中。
没有initial会有点困难,
[stack.append(function(stack.pop(), e)) or stack[0]
for it in [iter(sequence)]
for stack in [[next(it)]]
for e in it][-1]
真的,此时您不妨使用for 语句。
但这会占用中间值列表的内存。对于很长的序列,这可能是个问题。但是我们也可以通过使用生成器表达式来避免这种情况。
这样做很棘手,所以让我们从一个更简单的示例开始并逐步完成。
stack = [initial]
[stack.append(function(stack.pop(), e)) for e in sequence]
stack.pop() # returns the answer
它会计算答案,但也会创建一个无用的Nones 列表。我们可以通过将其转换为列表推导式中的生成器表达式来避免这种情况。
stack = [initial]
[_ for _s in (stack.append(function(stack.pop(), e)) or ()
for e in sequence)
for _ in _s]
stack.pop()
列表推导耗尽了更新堆栈的生成器,但本身返回一个空列表。这是可能的,因为内部循环总是有零次迭代,因为_s 总是一个空元组。
如果最后一个_s 有一个元素,我们可以将stack.pop() 移动到里面。不过,那个元素是什么并不重要。因此,我们将[None] 链接为最终的_s。
from itertools import chain
stack = [initial]
[stack.pop()
for _s in chain((stack.append(function(stack.pop(), e)) or ()
for e in sequence),
[[None]])
for _ in _s][0]
同样,我们有一个单项列表理解。我们还可以将chain 实现为生成器表达式。您已经了解了如何使用单项列表将 stack 变量移到内部。
[stack.pop()
for stack in [[initial]]
for _s in (
x
for xs in [
(stack.append(function(stack.pop(), e)) or ()
for e in sequence),
[[None]],
]
for x in xs)
for _ in _s][0]
我们还可以从两个参数reduce的序列中获取初始值。
[stack.pop()
for it in [iter(sequence)]
for stack in [[next(it)]]
for _s in (
x
for xs in [
(stack.append(function(stack.pop(), e)) or ()
for e in it),
[[None]],
]
for x in xs)
for _ in _s][0]
这太疯狂了。但它有效。所以是的,可能通过理解获得“类似减少的功能”。这并不意味着您应该。七个fors太难了!