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

これは機能しますが、last+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は「と」と言っているのでlast、2つを足し合わせることができません。intreclist

さて、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)ます。このコマンドは、からの最初の出現を削除します。最後のオカレンスを削除したいと思います。lastnew_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

関数は常にリストを返す必要があります。空のリストの場合は空のリスト、要素が1つしかない場合は、要素が1つだけのリスト

ただし、コードは1つの要素を含むリストではなく、1つの要素を返します。

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の合計をに加算し、その合計をに加算します。それを利用してみましょう。abcd

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)

今は番号のコピーを保存することすらにしないことに注意してください。最初の要素以外のすべてのスライスとして、それを次の再帰に渡すこともできます。また、からの最初の要素を使用numbersして合計(numbers[0])を作成します。

また、これまでの累積合計を0から開始して渡します。つまり、再帰関数の終了条件を変更する必要があります。基本的にリストの先頭に追加[0]しているので、常に次の要素と合計するようにします。

これで、必要な処理が実行されます。

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