-1

数値のパーティションを提供するコードを作成しようとしています.これまでのところ、これを思いつきました(Googleで見つかりました)。

def gen(n):
           # tuple version
           if n == 0:
               yield ()
               return

           for p in gen(n-1):
               yield (1, ) + p
               if p and (len(p)<2 or p[1] > p[0]):
                   yield (p[0] + 1, ) + p[1:]

print(list(gen(5)))

誰かがこの再帰関数がどのように機能するかを理解するのを手伝ってくれたら本当にありがたいです.助けてください.ありがとう.

4

2 に答える 2

3

何が起こっているのかを理解するために、いくつかの連続的に増加する の値に対するジェネレーターの出力を出力すると役立ちますn

>>> for i in range(5):
        print(list(gen(i)))

[()]
[(1,)]
[(1, 1), (2,)]
[(1, 1, 1), (1, 2), (3,)]
[(1, 1, 1, 1), (1, 1, 2), (2, 2), (1, 3), (4,)]

各シーケンスの計算は、その前のシーケンスに基づいています。これがどのように機能するかを行ごとに説明します。

if n == 0:
    yield ()
    return

ジェネレーターの最初の数行は、nがゼロの基本ケース用です。このreturnステートメントは、残りのコードを続行するのではなく、空のタプルを生成した後に終了します。

for p in gen(n-1):

これは、関数の再帰的なステップです。はジェネレーターなのでgen、ループで実行されるため、残りのコードはp、再帰の結果から異なる値を取得して繰り返し実行されます。

    yield (1, ) + p

これは重要な行です。1これが行うことは、 aを value の先頭に連結することによって形成された新しいタプルをジェネレーターから生成することですp。が空のタプルの場合p、これは 1 タプルになります。pすでにいくつかの値がある場合、タプルは長くなります。

    if p and (len(p)<2 or p[1] > p[0]):

これは複雑な条件です。2 番目のチェックは、最初の部分がすでに空であることを除外しているため、len(p)<2実際には と書くことができます。len(p)==1p andp

p渡すために持つことができる値には 2 種類あります。p値が 1 つだけであるか、複数の値があり、最初の値が 2 番目の値よりも小さいかのいずれかです。合格しますが、(3,)合格しません。(1,2)(1,1,1)

        yield (p[0] + 1, ) + p[1:]

これは別のタプル連結です。の最初の値を 1 増やしてから、 (スライスを使用して)pの残りの値と連結します。pそう(3,)なり(4,)ます (スライスが空の状態で)、(1,2)なります(2,2)など。

それでは、上記の結果を見てみましょう。

[()]

0にn等しい場合、基本ケースがヒットし、単一の空のタプルが生成されます。

[(1,)]

1にn等しい場合、ループは 1 回実行(1,)され、空のタプルに連結され、 1-tuple が生成され(1,)ます。が空であるため、条件の最初の部分はif渡されません。p

[(1,1), (2,)]

2にn等しい場合、ループは 1 回だけ実行されます。まず、それ自体を(1,1)連結して を取得します。しかし今回は、値が 1 つしかないため、ブロックが実行されます。したがって、それも得られます。そのスライス部分は空のタプルですが、最初の部分は.(1,)(1,1)ifp(p[0]+1,) + p[1:](2,)

[(1,1,1), (1,2), (3,)]

これで、ループが複数回実行されるようになりました。(1,)ただし、最初は の前に別のものを連結しますが(1,1)ifステートメントの条件が満たされないため、それがすべてです。ただし、2 番目のパスでは、2 つの値が生成されます。一度連結さ(1,)れて(2,)から にインクリメント(2,)され(3,)ます。

[(1, 1, 1, 1), (1, 1, 2), (2, 2), (1, 3), (4,)]

これはあなたに任せます。上記の場合と同様に、pは呼び出し ( ) の前のレベルからの各値を受け取り、(1,1,1), (1,2), (3,)各値に対して 1 つまたは 2 つの新しい結果を生成します。

于 2013-02-21T23:32:34.650 に答える
0

yield関数をジェネレーターに変換します。良い説明については、この回答を読んでください。

基本的に、結果のリストを一度に作成してから返すのではなく、次のようにします。

def f():
    output = []

    for i in range(10):
        output.append(i + 3)

    return output

yield要求した場合にのみ項目を生成するジェネレーターを作成できます。

def f():
    for i in range(10):
        yield i + 3

無限ジェネレーターを作成することも可能です:

def f():
    a = 0
    b = 1

    while True:
        yield b

        a, b = b, a + b

反復するf()と、フィボナッチ数列の項が吐き出され続けます。

于 2013-02-21T20:52:21.570 に答える