序章
PHP のバージョン 5.5 以降、 generatorsなどの優れた機能があります。公式のマニュアル ページについては繰り返しませんが、イテレータを簡単に定義するには非常に便利です。最もよく知られているサンプルは次のとおりです。
function xrange($from, $till, $step)
{
if ($from>$till || $step<=0)
{
throw new InvalidArgumentException('Invalid range initializers');
}
for ($i = $from; $i < $till; $i += $step)
{
yield $i;
}
}
//...
foreach (xrange(2, 13, 3) as $i)
{
echo($i.PHP_EOL); // 2,5,8,11
}
generator は実際には関数ではなく、具象クラスのインスタンスです。
get_class(xrange(1, 10, 1)); // Generator
問題
RTM の作業は終わり、私の質問に移りましょう。フィボナッチ数のジェネレーターを作成したいとします。通常、それらを取得するには、単純な関数を使用できます。
function fibonacci($n)
{
if(!is_int($n) || $n<0)
{
throw new InvalidArgumentException('Invalid sequence limit');
}
return $n < 2 ? $n : fibonacci($n-1) + fibonacci($n-2);
}
var_dump(fibonacci(6)); // 8
これを、最後のメンバーだけでなく、シーケンスを保持するものに変換しましょう。
function fibonacci($n)
{
if (!is_int($n) || $n<0)
{
throw new InvalidArgumentException('Invalid sequence limit');
}
if ($n<2)
{
return range(0, $n);
}
$n1 = fibonacci($n-1);
$n2 = fibonacci($n-2);
return array_merge($n1, [array_pop($n1)+array_pop($n2)]);
}
//...
foreach (fibonacci(6) as $i)
{
echo($i.PHP_EOL); // 0,1,1,2,3,5,8
}
完全なシーケンスで配列を返す関数ができました
質問
fibonacci
最後に、質問の部分: 最新の関数を変換して、配列に値を保持するのではなく、値を生成するにはどうすればよいですか? 私は大きくなる可能性があるので、サンプル$n
のようにジェネレーターの利点を利用したいと考えています。xrange
擬似コードは次のようになります。
function fibonacci($n)
{
if (!is_int($n) || $n<0)
{
throw new InvalidArgumentException('Invalid sequence limit');
}
if ($n<2)
{
yield $n;
}
yield fibonacci($n-2) + fibonacci($n-1);
}
しかし、再帰は値Generator
ではなくクラスのオブジェクトを引き起こすため、このように処理することはできないため、これは明らかにがらくたです。int
ボーナス:フィボナッチ数列を取得することは、より一般的な質問のサンプルにすぎません:一般的なケースで再帰を伴うジェネレーターを使用する方法は?もちろん、標準のIteratorを使用することも、再帰を避けるために関数を書き直すこともできます。しかし、私はジェネレーターでそれを達成したいと考えています。これは可能ですか?これをそのように使用する価値はありますか?