如何使用map和reduce在Python中逐步编写一个函数列表

4

给定一个函数列表(functions)和一个整数n,我正在尝试找出一种逐步组合它们并返回每个逐步结果列表的方法,如下所示:

compose_step([lambda x: x+3, lambda x: x+5, lambda x: x+1], 8) --> [8, 11, 16, 17]

目前,我已经学会如何编写函数列表并返回结果,代码如下:

def compose(functions, n):
    def compose2(f,g):
        return lambda x: f(g(x))
    composedFunction = functools.reduce(compose2, functions, lambda x: x)
    return composedFunction(n)

然而,我非常困惑如何跟踪每个步骤并将其作为列表返回。我假设我需要以某种方式使用 map 将每个逐步的部分映射到列表中。我还想出了一种方法,可以将列表中的所有函数应用于 n,如下所示:

def apply_all_functions(functions, n):
    answerList = list(map(methodcaller('__call__', n), functions)))
    return answerList

我在考虑如何使用composeFunction函数来组合一系列逐步函数,直到完全组合成的函数,并将其作为我的新列表用于apply_all_functions以达到预期的结果。但目前,我感到相当困惑。


你能解释一下你在这里的目的吗?我不明白你的输入和期望输出是什么。 - anishtain4
3个回答

4
您可以使用itertools.accumulate与组合函数一起使用。
from itertools import accumulate

def compose(f, g):
    return lambda x: f(g(x))

funcs = [lambda x: x, lambda x: x+3, lambda x: x+5, lambda x: x+1]

print([f(8) for f in accumulate(funcs, compose)])
# [8, 11, 16, 17]

1

itertools.accumulate 是最好的选择,但如果你想知道如何自己实现,下面是一种方法

def apply_all (x, f = None, *fs):
  if f is None:
    return []
  else:
    next = f (x)
    return [ next ] + apply_all(next, *fs)

funcs = \
  [ lambda x: x
  , lambda x: x+3
  , lambda x: x+5
  , lambda x: x+1
  ]

print(apply_all(8, *funcs))
# [ 8, 11, 16, 17 ]

如果您需要原始问题中的表单。
def apply_all (fs, x):
  if not fs:
    return []
  else:
    next = fs[0](x)
    return [ next ] + apply_all(fs[1:], next)

funcs = \
  [ lambda x: x
  , lambda x: x+3
  , lambda x: x+5
  , lambda x: x+1
  ]

print(apply_all(funcs, 8))
# [ 8, 11, 16, 17 ]

上面的表单操作涉及到 fs[0]fs[1:],这表明它可以被表示为一个普通的 reduce
from functools import reduce

def apply_all (fs, x):
  def reducer (acc, f):
    (seq, x) = acc
    next = f (x)
    return (seq + [next], next)
  return reduce(reducer, fs, ([], x)) [0]

funcs = \
  [ lambda x: x
  , lambda x: x+3
  , lambda x: x+5
  , lambda x: x+1
  ]

print(apply_all(funcs, 8))
# [ 8, 11, 16, 17 ]

0

你也可以使用 itertools.accumulate 并设置初始值:

from itertools import accumulate


def compose(data, funcs):
    yield from accumulate(funcs, lambda data, f: f(data), initial=data)


funcs = [lambda x: x+3, lambda x: x+5, lambda x: x+1]
init = 8
print(list(compose(init, funcs)))
# [8, 11, 16, 17]

如果您不想要中间结果,可以使用 functools.reduce 进行类似的操作。

这与 @Patrick 的答案类似,但是 accumulate 会逐步应用每个函数并逐一生成结果,而不是生成组合函数。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接