1

我是 python 新手,正在尝试解决我的作业...我正在尝试创建一个递归函数,该函数采用数字列表 [a, b, c....] 并将其转换为以下列表:[a , a+b, a+b+c, ....]。

这是我的代码:

def rec_cumsum(numbers):
    ''' Input: numbers - a list of numbers,
            Output: a list of cumulative sums of the numbers'''
    new_list=numbers
    last=new_list[-1]
    if numbers==[]:
         return numbers
    if len(numbers) == 1:
         return numbers[0]
    new_list.remove(last)
    rec= rec_cumsum(new_list)
    new_list.append(rec+last)
    return last+rec

这可行,但因为我使用了最后+rec 的return,所以我不能使用return 来取回列表(new_list)。请向我解释我做错了什么...谢谢!

4

2 回答 2

6

让我们编写一些测试用例并实践一些测试驱动的开发:

tests = [[],         # Desired answer: []
         [1],        # [1]
         [1,2],      # [1, 3] 
         [1,2,3],    # [1, 3, 6]
         [1,2,1,3]]  # [1, 3, 4, 7]
for t in tests:
    print(rec_cumsum(t))

如果我们将其添加到您的代码中并运行它,我们会得到

    last=new_list[-1]
IndexError: list index out of range

为什么是这样?显然 -1 是一个超出范围的索引。为什么没有new_list-1索引?

啊哈。如果new_list为空,就会发生这种情况。所以我们需要首先解决基本情况。当我们这样做的时候,让我们也使用@MartijnPieters 的建议:

if len(numbers) <= 1:
     return numbers

获得

def rec_cumsum(numbers):
    ''' Input: numbers - a list of numbers,
            Output: a list of cumulative sums of the numbers'''
    if len(numbers) <= 1:
         return numbers
    new_list=numbers
    last=new_list[-1]
    new_list.remove(last)
    rec = rec_cumsum(new_list)
    new_list.append(rec[-1]+last)
    return last+rec

现在再次运行测试。这次我们得到

    return last+rec
TypeError: unsupported operand type(s) for +: 'int' and 'list'

所以现在 Python 说lastis anintrecis a list,我们不能把两者加在一起。

好的,rec应该是一个列表,因为它是rec_cumsum(new_list). 应该换last+rec什么?

让我们考虑一个具体的例子。如果rec是,[a, a+b]那么我们要返回[a, a+b, a+b+c]。我们如何形成a+b+c

如何将最后一个元素添加到最后rec一个元素numbers

rec[-1]+last

我们想将其附加到末尾rec

rec.append(rec[-1]+last)

让我们做出改变,看看会发生什么。但是在我们编辑的同时,让我们也清理一些我们从未使用过的代码。我们可以删除new_list.append(rec[-1]+last)

def rec_cumsum(numbers):
    ''' Input: numbers - a list of numbers,
            Output: a list of cumulative sums of the numbers'''
    if len(numbers) <= 1:
         return numbers
    new_list=numbers
    last=new_list[-1]
    new_list.remove(last)
    rec = rec_cumsum(new_list)
    rec.append(rec[-1]+last)
    return rec

现在我们的程序返回

[]
[1]
[1, 3]
[1, 3, 6]
[2, 3, 4, 7]

万岁,我们的程序运行没有错误。但是等等......它返回错误的结果。看最后一行。

rec_cumsum([1,2,1,3])正在返回[2,3,4,7],而正确答案是[1,3,4,7]。为什么第一个数字是错误的?

它与new_list.remove(last). 此命令删除第一次出现的lastfrom new_list。我们要删除最后一次出现。

所以相反,让我们使用

new_list = numbers[:-1]

所以程序变成了:

def rec_cumsum(numbers):
    ''' Input: numbers - a list of numbers,
            Output: a list of cumulative sums of the numbers'''
    if len(numbers) <= 1:
         return numbers
    new_list=numbers[:-1]
    last=numbers[-1]
    rec = rec_cumsum(new_list)
    rec.append(rec[-1]+last)
    return rec

运行测试。有用!现在回顾一下我们的解决方案,看看如何将其收紧并变得更优雅,这是一个很好的做法。我看到我们使用new_listlast作为临时变量。我们真的需要它们吗?

def rec_cumsum(numbers):
    if len(numbers)<=1:
        return numbers
    result = rec_cumsum(numbers[:-1])
    result.append(result[-1]+numbers[-1])
    return result
于 2012-11-18T13:20:59.580 回答
3

你的函数应该总是返回一个列表;对于空列表的情况,一个空列表,对于只有一个元素的情况,一个只有一个元素的列表

但是您的代码返回一个元素,而不是一个包含一个元素的列表:

if len(numbers) == 1:
     return numbers[0]

将其更改为仅返回numbers

if len(numbers) == 1:
     return numbers

您可以将其与其他最终状态测试结合使用:

if len(numbers) < 2:
     return numbers

下一个问题是您在创建变量时没有创建列表的副本new_list;您创建对同一个列表的引用,您必须使用切片或创建一个明确的新列表:

new_list = numbers[:]

如果您无论如何要从该列表中删除一个值,您也可以稍微调整一下切片,并在测试numbers放置(为什么要这样做):

if len(numbers) < 2:
     return numbers
new_list = numbers[:-1]
last = numbers[-1]

在您的代码中,您实际上没有计算总和;您的号码不会添加任何内容。您从不添加a,bc。此外,您似乎专注于最后一个数字,而您的作业表明您需要将第一个值与列表的其余部分相加。

那里有一个模式。不仅你a加到b,而且a+的总和b被加到c,然后那个总和被加到d,等等。让我们利用它:

def rec_cumsum(numbers, culmulated_sum=0):
    if len(numbers) < 1:
        return numbers
    sum = numbers[0] + culmulated_sum
    return [sum] + rec_cumsum(numbers[1:], sum)

请注意,我现在什至不费心存储数字副本;也可以将它作为除第一个元素之外的所有内容的一部分传递给下一个递归。我们还使用 from 的第一个元素numbers来创建我们的 sum ( numbers[0])。

此外,我们现在传递到目前为止的累积和,从 0 开始;这意味着我们需要改变递归函数的结束条件;我们本质上是添加[0]到列表的开头,并且我们要确保始终将其与下一个元素相加。

这现在可以满足您的需要:

>>> rec_cumsum([5, 1, 10, 2, 3])
[5, 6, 16, 18, 21]
于 2012-11-18T12:43:02.847 回答