最近、私は重要な制約を持つ特定のシーケンスを生成する関数を書きました。問題は、自然な再帰的な解決策で発生しました。今では、比較的小さな入力の場合でもシーケンスが数千になるため、すべてのシーケンスをリストに入力するのではなく、アルゴリズムをジェネレーターとして使用したいと思います。
例を示します。再帰関数で文字列のすべての順列を計算したいとします。次の単純なアルゴリズムは、追加の引数「ストレージ」を取り、それが見つかるたびに置換を追加します。
def getPermutations(string, storage, prefix=""):
if len(string) == 1:
storage.append(prefix + string) # <-----
else:
for i in range(len(string)):
getPermutations(string[:i]+string[i+1:], storage, prefix+string[i])
storage = []
getPermutations("abcd", storage)
for permutation in storage: print permutation
(非効率性については気にしないでください。これは単なる例です。)
次に、関数をジェネレーターに変換します。つまり、ストレージリストに追加するのではなく、順列を生成します。
def getPermutations(string, prefix=""):
if len(string) == 1:
yield prefix + string # <-----
else:
for i in range(len(string)):
getPermutations(string[:i]+string[i+1:], prefix+string[i])
for permutation in getPermutations("abcd"):
print permutation
このコードは機能しません(関数は空のジェネレーターのように動作します)。
何か不足していますか?上記の再帰アルゴリズムを反復アルゴリズムに置き換えることなくジェネレータに変換する方法はありますか?
yield from getPermutations(string[:i] + string[i+1:])
で置き換えることができます。これは多くの点でより効率的です!