Python递归挑战[关闭]
Posted
技术标签:
【中文标题】Python递归挑战[关闭]【英文标题】:Python recursion challenge [closed] 【发布时间】:2017-01-25 10:58:08 【问题描述】:我目前正在学习 Python 和计算理论课程,最近在期中考试中遇到了一个我根本无法解决的难题。它涉及为添加数字的程序编写代码。我相信这个问题应该使用递归。我不记得问题的具体措辞,但这是基本思想。
实现multiadder(n)
函数,该函数接受一个非负整数n
并将n
任意值相加。要添加的每个值都必须作为单独的调用编写。例如:
>>> multi_three = multiadder(3)
>>> multi_three(1)(2)(3)
6
>>> multiadder(5)(1)(2)(3)(4)(5)
15
代码必须通过填空来编写。
def multiadder(n):
assert n > 0
if _________________________ :
return _________________________
else:
return _________________________
我们在课堂上讨论的主题是高阶函数、递归、lambda 和控制语句。我们不允许使用列表和集合之类的数据结构,也不允许导入任何东西。
请有人帮忙。这是我唯一不能参加考试的问题!
【问题讨论】:
如果允许您向multiadder
添加具有默认值的第二个参数,这很容易。既然你说你不记得确切的问题,你确定这里的空格是正确的吗?
我真的不确定是否可以填充给定的结构。您需要同时跟踪累加器状态和级别状态(知道何时停止返回可调用对象并返回累加值),并且您只有一个变量可以使用,n
。
加数为任意整数。我不记得问题的确切措辞,但我肯定知道的代码结构是正确的。教授有可能犯了错误,但据我所知,这将是他在考试中的第一个错误。
这不是将 Stack Overflow 用作代码编写服务的例子吗?
这并不宽泛。答案很简短。
【参考方案1】:
试试这个:
def multiadder(n):
assert n > 0
if n == 1:
return lambda t: t
else:
return lambda a: lambda b: multiadder(n-1)(a+b)
if __name__ == '__main__':
print(multiadder(5)(1)(2)(3)(4)(5))
对于n == 1
,结果必须是返回输入的函数。
对于n > 1
,通过添加输入包装n-1
的结果。
这也适用于连接字符串和其他累加操作:
>>> multiadder(3)('p')('q')('r')
pqr
【讨论】:
如果我为multiadder(1)(2)(3)
运行这个,我会得到 TypeError: 'int' object is not callable
@AnthonyBlackshaw 这种行为是意料之中的。 multiadder(2)(2)(3)
是你应该做的
@MosesKoledoye 对不起,你是对的,我错过了阅读最初的例子。
第一个参数是连续调用的次数,试试:multiadder(3)(1)(2)(3)
【参考方案2】:
你可以这样做,但它几乎是不可读的。我希望这些解释会有所帮助:
def multiadder(n):
assert n > 0
if n == 0:
return 0
else:
return (lambda f: lambda i, n, sm: f(f, i, n, sm))(
lambda rec, i, n, sm: sm+i if n == 0 else lambda j: rec(rec, j, n-1, sm+i)
)(0, n, 0)
查看它在repl.it 上运行。
工作原理
返回值由三大部分组成:
(lambda f: lambda i, n, sm: f(f, i, n, sm))
简而言之,这个函数给函数赋值,所以可以递归调用。更详细地说:
它需要一个函数f
,它本身必须接受 4 个参数,其中第一个参数应该是自引用。
这里返回的函数接受其他三个参数,并返回对f
的递归调用。
第二部分才是真正的核心:
(lambda rec, i, n, sm: sm+i if n == 0 else lambda j: rec(rec, j, n-1, sm+i))
这作为参数传递给上面的第一个函数,使递归成为可能。 这个函数接受上面提到的 4 个参数,并应用特定的逻辑:
i
是必须添加的数字
n
是在此之后仍期望的值的数量
sm
是迄今为止的累计总和(不包括i
)
根据是否需要更多值,此函数返回最终结果 (sm+i
) 或
一个带有一个参数的函数,它的作用与此处描述的相同(递归),减少了n
,并调整了总和。
最后将初始值传递给上面:
(0, n, 0)
意思是,我们从数字 0(虚拟)、n
期望值和当前总和 0 开始。
注意
由于上述代码中的递归不涉及对multiladder
的调用,并且断言确实排除了if
条件为真,所以我们可以不用if...else
:
def multiadder(n):
assert n > 0
return (lambda f: lambda i, n, sm: f(f, i, n, sm))(
lambda rec, i, n, sm: sm+i if n == 0 else lambda j: rec(rec, j, n-1, sm+i)
)(0, n, 0)
【讨论】:
看起来像教堂算术,有点 如果assert n > 0
那么if n == 0: return 0
将永远不会被执行,不是吗?
确实,@boardrider,我在接近尾声的回答中写到了这一点。【参考方案3】:
您还可以定义一个内部辅助函数 (loop
),它将和状态 (acc
) 跟踪为计数器状态 (n
) 递减
def multiadder(n):
def loop(acc,n):
if n == 0:
return acc
else:
return lambda x: loop(acc+x, n-1)
return loop(0,n)
print(multiadder(3)(1)(2)(3)) # 6
print(multiadder(5)(1)(2)(3)(4)(5)) # 15
它不像 DarkKnight 的答案那么优雅,但对于初学者来说可能更容易概念化。事实上,这种模式非常有用且用途广泛,我用它来定义几乎所有的递归过程。
def some_recursive_func:
def loop(...state_parameters):
if base_condition:
return answer
else:
return loop(...updated_state_variables)
return loop(...initial_state_variables)
我们对该模式所做的唯一调整是将if
表达式的递归分支包装在lambda x: ...
中——这是因为multiadd
旨在返回函数,直到应用n
返回的函数。
还有一个,只是为了好玩,使用传奇的Y-combinator。这可能不符合您的讲师提供的标准,但看到它还是很酷的。 Multiline lambdas in python are not really a thing 所以可读性会受到一点影响。
U = lambda f: f(f)
Y = U (lambda h: lambda f: f (lambda x: h (h) (f) (x)))
multiadder = Y (lambda f: lambda acc: lambda n:
acc if n == 0 else lambda x: f (acc+x) (n-1)
) (0)
print(multiadder(3)(1)(2)(3)) # 6
print(multiadder(5)(1)(2)(3)(4)(5)) # 15
或者,如果您愿意,您仍然可以使用 def
语法定义 multiadder
def multiadder(n):
return Y (lambda f: lambda acc: lambda n:
acc if n == 0 else lambda x: f (acc+x) (n-1)
) (0) (n)
它的工作方式相同。
我强烈建议您逐步跟踪评估以了解其工作原理。在理解这些高阶函数时可以获得一些巨大的见解。
【讨论】:
您介意扩展一下您的答案吗?这里似乎有什么有价值的东西,但我还没有弄清楚。 (这里是初学者) @DanielG 当然,我很乐意提供帮助。是否有特定的部分令人困惑?也许让我知道您理解的部分,我可以尝试详细说明其余部分 不,答案并不令人困惑。我只是不太明白嵌套是从哪里来的。在 DarkKnight 的回答中,我们在else
分支中有两个 lambda,因此在每次递归时,嵌套都会增加。
是的,本地定义的函数是我们在课堂上学到的,并在测试中的许多地方使用过。如果可能的话,我会这样做。
@DanielG 对 DarkKnight 的回答的“诀窍”是她/他在双 lambda 下应用了两个函数,因此嵌套级别永远不会超过 2 深。【参考方案4】:
起初,multiadder 似乎需要两个输入才能工作,但答案很简单。我不认为“Python 简介”课程需要兰巴函数等。
这是最终答案:
def multiadder(n):
assert n > 0
if n == 1:
return 1
else:
return n + multiadder(n - 1)
下图解释了 n = 4 的工作原理:
multiadder(4)
|
return 4 + multiadder(3)
|
return 3 + multiadder(2)
|
return 2 + multiadder(1)
|
return 1
所以 n = 4 的最终结果是 4 + 3 + 2 + 1 = 10。
【讨论】:
我认为您误读了问题描述。它不应该将第一个n
数字相加,而是链式函数调用中提供的特定 n
数字相加。
哦,是的,你是对的。我的答案只是一个累积的总和......无论如何我都会留下它。感谢您指出这一点 Blckknght以上是关于Python递归挑战[关闭]的主要内容,如果未能解决你的问题,请参考以下文章