我试图递归地找到一个列表的总和如下(我知道有一个简单的sum()函数和大量其他方法):
def rsum(x):
if not (x):
return 0
else:
sum = x[0] + rsum(x.pop(0))
return sum
然而,Python一直告诉我x是一个int而且不能有operator []。我该如何解决?
对于那些认为我懒得在这里提出这个问题的人:我到处都看,但仍然不知道如何让Python明白x
不应该是一个int。
答案 0 :(得分:5)
x.pop(0)
将删除第一个项目并将其返回。并且您将其传递给rsum
,它正在尝试x[0]
,但x
现在是一个数字。这就是它失败的原因。
相反,首先使用pop
,将x
传递给rsum
,这样
def rsum(x):
if not x:
return 0
else:
return x.pop() + rsum(x)
print rsum([1, 2, 3])
# 6
如果你想避免改变原始对象,那么使用slicing创建没有第一个元素的新列表,就像这样
def rsum(x):
if not x:
return 0
else:
return x[0] + rsum(x[1:])
print rsum([1, 2, 3])
# 6
由于您正在学习递归,我希望您也考虑Tail Call optimization。你可以像这样改变你的功能
def rsum(x, total):
if not x:
return total
else:
return rsum(x[1:], total + x[0])
print rsum([1, 2, 3], 0)
# 6
在早期的情况下,在你达到基本条件(if not x:
)之前,当前的函数不能从内存中取出(因为x[0]
或x.pop()
在当前堆栈中并且它们是必须添加递归调用的结果实际从当前函数返回)。因此,当您在一个非常大的列表上运行此函数时,它将耗尽堆栈空间。但是,在TCO版本中,您将返回另一个函数调用的结果。因此,当前的功能不必在内存中。
注意:也就是说,Python并不支持Tail Call Optimization。阅读BDFL(Guido)对此here的评论。
答案 1 :(得分:2)
如果您遇到的错误似乎对您希望对象拥有的值有意义,请尝试打印它以查看所具有的
值:def rsum(x):
print(x)
if not (x):
return 0
else:
sum = x[0] + rsum(x.pop(0))
return sum
rsum([1,2,3])
给出这个输出:
[1, 2, 3]
1
所以,第一次时间你调用rsum
它有一个预期的列表; 第二时间它有一个数字。您可以在交互式解释器中进行游戏,找出原因:
>>> x = [1,2,3]
>>> x.pop(0)
1
>>> x
[2, 3]
因此,pop
修改了列表,但调用的结果是已删除的项目。你可以用这个事实来得出这样的东西:
sum = x.pop(0) + rsum(x)
答案 2 :(得分:1)
很简单的例子:
def rec_sum(x, n):
if not n:
return x[0]
return x[n] + rec_sum(x, n-1)
print rec_sum(x, len(x)-1)
此版本比 thefourtheye 发布的所有示例更有效,因为在Python中,每个 x [1:] 都会生成新列表。为什么要在使用原始列表时执行此操作?此外,没有理由像 .pop
那样进行操作