Rekursive Generatoren in PHP
Seit Version 5.5 in PHP gibt es so etwas Tolles wieGeneratoren. Ich werde die offizielle Handbuchseite nicht wiederholen, aber sie eignen sich hervorragend für die kurze Definition von Iteratoren. Das bekannteste Beispiel ist:
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
}
und generator ist eigentlich keine Funktion, sondern eine Instanz einer konkreten Klasse:
get_class(xrange(1, 10, 1)); // Generator
Fertig mit RTM-Dingen, nun zu meiner Frage. Stellen Sie sich vor, wir möchten einen Generator für erstellenFibonacci-Zahlen. Um diese zu erhalten, können wir normalerweise die einfache Funktion verwenden:
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
Lassen Sie uns dies in etwas verwandeln, das giltSequenz und nicht nur das letzte Mitglied:
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
}
Wir haben jetzt eine Funktion, die ein Array mit voller Sequenz zurückgibt
Zum Schluss noch die Frage: Wie kann ich meine neueste verwandelnfibonacci
funktionieren so wird esAusbeute meine Werte, die nicht in einem Array enthalten sind? Meine$n
kann groß sein, also möchte ich die Vorteile von Generatoren nutzen, wie inxrange
Probe. Pseudocode ist:
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);
}
Aber das ist natürlich Mist, da wir nicht so damit umgehen können, weil Rekursion ein Klassenobjekt verursachtGenerator
und nichtint
Wert.
Bonus: Abrufen der Fibonacci-Sequenz ist nur ein Beispiel für eine allgemeinere Frage: Wie werden Generatoren mit Rekursion im allgemeinen Fall verwendet? Natürlich kann ich Standard verwendenIterator dafür oder schreiben Sie meine Funktion um, um eine Rekursion zu vermeiden. Aber ich möchte das mit Generatoren erreichen. Ist das möglich? Lohnt es sich, dies so zu nutzen?