“编写一个递归函数,”listSum“,它获取整数列表并返回列表中所有整数的总和”。
示例:
>>>> listSum([1,3,4,5,6])
19
我知道如何以另一种方式做到这一点,但不是以递归的方式。
def listSum(ls):
i = 0
s = 0
while i < len(ls):
s = s + ls[i]
i = i + 1
print s
我需要基本的方法来执行此操作,因为不允许使用特殊的内置函数。
答案 0 :(得分:81)
每当遇到这样的问题时,请尝试用相同的函数表示函数的结果。
在您的情况下,您可以通过添加第一个数字来获得结果,其结果是使用列表中的其余元素调用相同的函数。
例如,
listSum([1, 3, 4, 5, 6]) = 1 + listSum([3, 4, 5, 6])
= 1 + (3 + listSum([4, 5, 6]))
= 1 + (3 + (4 + listSum([5, 6])))
= 1 + (3 + (4 + (5 + listSum([6]))))
= 1 + (3 + (4 + (5 + (6 + listSum([])))))
现在,listSum([])
的结果应该是什么?它应该是0.这被称为递归的基本条件。当满足基本条件时,递归将结束。现在,让我们尝试实现它。
这里最重要的是,拆分列表。您可以使用slicing来执行此操作。
简易版
>>> def listSum(ls):
... # Base condition
... if not ls:
... return 0
...
... # First element + result of calling `listsum` with rest of the elements
... return ls[0] + listSum(ls[1:])
>>>
>>> listSum([1, 3, 4, 5, 6])
19
尾调用递归
一旦你理解了上面的递归是如何工作的,你可以试着让它更好一些。现在,为了找到实际结果,我们也依赖于前一个函数的值。 return
语句无法立即返回值,直到递归调用返回结果。我们可以避免这种情况,将当前传递给函数参数,就像这样
>>> def listSum(ls, result):
... if not ls:
... return result
... return listSum(ls[1:], result + ls[0])
...
>>> listSum([1, 3, 4, 5, 6], 0)
19
在这里,我们将总和的初始值传递给参数,在listSum([1, 3, 4, 5, 6], 0)
中为零。然后,当满足基本条件时,我们实际上在result
参数中累加和,所以我们返回它。现在,最后一个return
语句有listSum(ls[1:], result + ls[0])
,我们将第一个元素添加到当前result
并再次传递给递归调用。
这可能是理解Tail Call的好时机。它与Python无关,因为它不进行Tail调用优化。
传递索引版本
现在,您可能认为我们正在创建这么多中间列表。我可以避免吗?
当然,你可以。您只需要接下来要处理的项目的索引。但现在,基本情况将有所不同。由于我们将要传递索引,我们如何确定整个列表的处理方式?好吧,如果索引等于列表的长度,那么我们已经处理了它中的所有元素。
>>> def listSum(ls, index, result):
... # Base condition
... if index == len(ls):
... return result
...
... # Call with next index and add the current element to result
... return listSum(ls, index + 1, result + ls[index])
...
>>> listSum([1, 3, 4, 5, 6], 0, 0)
19
内部功能版
如果现在查看函数定义,则会向其传递三个参数。假设您要将此功能作为API发布。当用户实际找到列表的总和时,是否方便传递三个值?
不。我们对于它可以做些什么呢?我们可以创建另一个函数,它是实际的listSum
函数的本地函数,我们可以将所有与实现相关的参数传递给它,就像这样
>>> def listSum(ls):
...
... def recursion(index, result):
... if index == len(ls):
... return result
... return recursion(index + 1, result + ls[index])
...
... return recursion(0, 0)
...
>>> listSum([1, 3, 4, 5, 6])
19
现在,当调用listSum
时,它只返回recursion
内部函数的返回值,该函数接受index
和result
参数。现在我们只传递这些值,而不是listSum
的用户。他们只需要传递要处理的列表。
在这种情况下,如果您观察参数,我们不会将ls
传递给recursion
,但我们正在其中使用它。由于封闭属性,ls
可以在recursion
内访问。
默认参数版本
现在,如果你想保持简单,不创建内部函数,你可以使用默认参数,比如
>>> def listSum(ls, index=0, result=0):
... # Base condition
... if index == len(ls):
... return result
...
... # Call with next index and add the current element to result
... return listSum(ls, index + 1, result + ls[index])
...
>>> listSum([1, 3, 4, 5, 6])
19
现在,如果调用者未明确传递任何值,则0
和index
将分配result
。
递归电源问题
现在,让我们将这些想法应用于其他问题。例如,让我们尝试实现power(base, exponent)
函数。它会将base
的值提升为幂exponent
。
power(2, 5) = 32
power(5, 2) = 25
power(3, 4) = 81
现在,我们如何递归地执行此操作?让我们试着了解这些结果是如何实现的。
power(2, 5) = 2 * 2 * 2 * 2 * 2 = 32
power(5, 2) = 5 * 5 = 25
power(3, 4) = 3 * 3 * 3 * 3 = 81
嗯,所以我们明白了。 base
乘以自身,exponent
次给出结果。好的,我们如何处理它。让我们尝试使用相同的函数定义解决方案。
power(2, 5) = 2 * power(2, 4)
= 2 * (2 * power(2, 3))
= 2 * (2 * (2 * power(2, 2)))
= 2 * (2 * (2 * (2 * power(2, 1))))
如果将任何东西提升到1,应该是什么结果?结果将是相同的数字,对吗?我们得到了递归的基本条件: - )
= 2 * (2 * (2 * (2 * 2)))
= 2 * (2 * (2 * 4))
= 2 * (2 * 8)
= 2 * 16
= 32
好吧,让我们实现它。
>>> def power(base, exponent):
... # Base condition, if `exponent` is lesser than or equal to 1, return `base`
... if exponent <= 1:
... return base
...
... return base * power(base, exponent - 1)
...
>>> power(2, 5)
32
>>> power(5, 2)
25
>>> power(3, 4)
81
好的,如何定义Tail调用优化版本呢?让我们将当前结果作为参数传递给函数本身,并在满足基本条件时返回结果。让我们保持简单并直接使用默认参数方法。
>>> def power(base, exponent, result=1):
... # Since we start with `1`, base condition would be exponent reaching 0
... if exponent <= 0:
... return result
...
... return power(base, exponent - 1, result * base)
...
>>> power(2, 5)
32
>>> power(5, 2)
25
>>> power(3, 4)
81
现在,我们在每个递归调用中减少exponent
值,在result
减少多个base
,并将其传递给递归power
调用。我们从值1
开始,因为我们正在反过来解决问题。递归将像这样发生
power(2, 5, 1) = power(2, 4, 1 * 2)
= power(2, 4, 2)
= power(2, 3, 2 * 2)
= power(2, 3, 4)
= power(2, 2, 4 * 2)
= power(2, 2, 8)
= power(2, 1, 8 * 2)
= power(2, 1, 16)
= power(2, 0, 16 * 2)
= power(2, 0, 32)
由于exponent
变为零,因此符合基本条件并返回result
,因此我们得到32
: - )
答案 1 :(得分:3)
提前退出是典型的递归函数。空的时候seq
是假的(因此当没有数字可以求和时)。
切片语法允许将序列传递给递归调用的函数,而不会在当前步骤中消耗整数。
def listSum(seq):
if not seq:
return 0
return seq[0] + listSum(seq[1:])
print listSum([1,3,4,5,6]) # prints 19
答案 2 :(得分:0)
def listSum(L):
"""Returns a sum of integers for a list containing
integers.
input: list of integers
output: listSum returns a sum of all the integers
in L.
"""
if L == []:
return []
if len(L) == 1:
return L[0]
else:
return L[0] + listSum(L[1:])
print listSum([1, 3, 4, 5, 6])
print listSum([])
print listSum([8])
答案 3 :(得分:0)
def power(a,b): #a^b
if b==0:
return 1
elif b>0:
return a * power(a,b-1)
elif b<0:
return power(a, b+1)/a
答案 4 :(得分:0)
另一个版本:
melt(df)
OUTPUT :
Day variable value
1 d1 A1 14
2 d2 A1 24
3 d3 A1 22
4 d4 A1 NA
5 d5 A1 NA
6 d6 A1 NA
7 d7 A1 NA
8 d8 A1 NA
9 d9 A1 NA
10 d10 A1 NA
11 d1 A2 9
12 d2 A2 15
13 d3 A2 34
14 d4 A2 2
15 d5 A2 12
16 d6 A2 34
17 d7 A2 234
18 d8 A2 34
19 d9 A2 NA
20 d10 A2 NA
21 d1 A3 3
22 d2 A3 4
23 d3 A3 19
24 d4 A3 76
25 d5 A3 34
26 d6 A3 34
27 d7 A3 23
28 d8 A3 24
29 d9 A3 37
30 d10 A3 44
按照@thefourtheye的示例,我们可以说:
def listSum(ls):
ls_len = len(ls)
# Base condition
if ls_len==1:
return ls[0]
if ls_len==0:
return None
# ls = listSum(ls[0:i]) + listSum(ls[i:])
elif ls_len%2==0:
i = int(ls_len/2)
return listSum(ls[0:i]) + listSum(ls[i:])
else:
i = int((ls_len-1)/2)
return listSum(ls[0:i]) + listSum(ls[i:])
基本条件:当listSum([1, 3, 4, 5, 6]) = listSum([1, 3]) + listSum([4, 5, 6])
= (listSum([1]) + listSum([3])) + (listSum([4]) + listSum([5, 6]))
= (listSum([1]) + listSum([3])) + (listSum([4]) + (listSum([5]) + listSum([6])))
仅具有一个元素时,返回此值。
答案 5 :(得分:0)
def listsum(list):
if len(list) == 1:
return list[0]
else:
return list[0] + listsum(list[1:])
print(listsum([1,5,9,10,20]))
此递归函数背后的基本思想是,我们要检查是否有显示为if len(list) == 1:
的基本情况。对于基本情况,我们只返回列表return list[0]
中的值,否则,列表中仍有多个元素。在else:
语句中,我们将列表中的第一个元素list[0]
添加到列表中的其余元素。这通过递归调用函数(列表递减1个元素)来显示: -索引0处的元素-listsum(list[1:])
,重复此过程,使列表变小,直到找到基本情况-长度为1的列表,然后得到最终结果。