Rekursive Suche Logik Problem
lima-city → Forum → Programmiersprachen → PHP, MySQL & .htaccess
break
code
element
ergebnis
funktion
knoten
kurzen code
machen
meinung
methode
null
paar
schleife
schnelligkeit
sinn
sparen
strich
vermeiden
verwendung
zeile
-
Hallo liebe Limanianer,
nachdem ich das vorherige Problem lösen konnte, stellt sich mir gleich ein neues in den Weg... Ich selbst habe das Gefühl, dass es sich hier um ein einfaches Logikproblem / Syntaxproblem handeln könnte.
Hier die rekursive Methode:
function GetChild($childID) { if($this->id == $childID){echo "Final: ".$this->id; return $this;} for ($i = 0; $i < count($this->children); $i++) if ($this->children[$i]->GetChild($childID) != null){ return $this->children[$i]; } return null; }
Und hier das Problem dazu:
Mit dieser Methode soll aus einer Baumstruktur ein spezifisches Element anhand seiner einmaligen ID gefunden und zurückgegeben werden. Durch die Verschachtelung wird das Ergebnis quasi in den ChildNodes gesucht und wenn gefunden durchgereicht bis zum aufrufenden Knoten. Doch an dieser Stelle findet er zwar den richtigen Knoten, gibt ihn aber nicht als Endgültiges Ergebnis zurück.
Hier ein Beispielaufruf:
echo " ".$_SESSION['naviTree']->rootNode->GetChild($_REQUEST['nodeID'])->id;
und die beiden Erwarteten Ausgaben:
"Final Gefunden: Sub21 FinalAusgabe:Sub2"
Sub2 ist in diesem Fall der Mutterknoten von Sub21
Ich hoffe, dass ich Alles korrekt und vollständig dargelegt habe.
Gruß und Dank im Voraus! -
Diskutiere mit und stelle Fragen: Jetzt kostenlos anmelden!
lima-city: Gratis werbefreier Webspace für deine eigene Homepage
-
Hallo
Ich glaube, es ist ein kleiner Logik-Fehler:
Sagen wir du hast folgenden Baum
__________E1_________
_____E2_______E3_____
___E4__E5___E6__E7___
E4 ist der Eintrag den du suchst.
Also geht der zuerst bei E1 durch. E1 ruft durch $this->children[$i]->GetChild($childID) E2 auf. E2 ruft durch $this->children[$i]->GetChild($childID) E4 auf.
Nun findet E4 raus dass er der richtige Eintrag ist -> er returnt sich selber - logisch.
Dann bekommt E2 dieses Resultat. Da es nicht null ist, returnt er wiederum: return $this->children[$i]; was dem Knoten E4 entspricht.
Nun kommt der Fehler
E1 kriegt die Message von E2 und returnt return $this->children[$i]; was dem Knoten E2 entspricht.
Der Code müsste folgendermassen geändert werden:
function GetChild($childID) { if($this->id == $childID){echo "Final: ".$this->id; return $this;} for ($i = 0; $i < count($this->children); $i++){ $searchresult = $this->children[$i]->GetChild($childID); if ($searchresult != null){ return $searchresult; } } return null; }
Hoffe ich hab den Codesnippet verstanden und geholfen
Beitrag zuletzt geändert: 16.3.2011 15:38:33 von misc -
Ahhh hervorragende Antwort^^ Manchmal verhindert die eigene Betriebsblindheit das man auf so triviale Lösungen selber kommt...
Besten dank dafür! -
Und für sauberen Quellcode solltest du darauf achten, möglichst nur ein 'return' in der Funktion zu haben.
Sähe dann so aus:
function GetChild($childID) { $result = null; if($this->id == $childID){echo "Final: ".$this->id; $result = $this;} else for ($i = 0; $i < count($this->children); $i++){ $searchresult = $this->children[$i]->GetChild($childID); if ($searchresult != null){ $result = $searchresult; } } return $result; }
Nur ein kleiner Hinweis von jemandem, der gerade ein paar Stunden mehrarbeit hatte, weil jemand sich nicht daran gehalten hat. -
Das mit dem Returnstatement ist genau wie Clean Code Development eine eigene Religion die kontrovers diskutiert wird. In den verschiedenen Lehrbüchern die ich mittlerweile zu C#, Java und PHP gelesen habe wird das immer verschieden gesehen. Zum einen ist es natürlich gut wenn man genau sehen kann, wo die Methode ihr Ende findet, andererseits kann hierüber eine Differenzierung stattfinden, wodurch weiterer redundanter Code übersprungen werden kann (Falls das Object == null ist z.B.). Allgemein lässt sich zusammenfassen, wenn dieses Verhalten nicht erwünscht wäre, dann hätten es doch kaum so viele Programmiersprachen als valides Verhalten zugelassen ^^
-
digital-diceland schrieb:
Und für sauberen Quellcode solltest du darauf achten, möglichst nur ein 'return' in der Funktion zu haben.
Sähe dann so aus:
...
Na, aber das sehe ich jetzt anders. Bei so einem kurzen Code ist das absolut überflüssig und generiert häufig mehr Zeilen. Wie bereits gesagt ist es verständlicherweise umstritten - schlussendlich muss man selbst (oder in grossen Projekten die Beteiligten) den Code verstehen. Genauso gut könnte man "break" vermeiden, es ist jedoch ebenfalls ein sehr vereinfachendes Element das einige Zeilen Code sparen kann. Ausserdem wird unter dem Strich wahrscheinlich beides gleich kompiliert / geparst.
Beitrag zuletzt geändert: 17.3.2011 20:35:18 von misc -
misc schrieb:
Na, aber das sehe ich jetzt anders. Bei so einem kurzen Code ist das absolut überflüssig und generiert häufig mehr Zeilen.
[...]
Genauso gut könnte man "break" vermeiden, es ist jedoch ebenfalls ein sehr vereinfachendes Element das einige Zeilen Code sparen kann. Ausserdem wird unter dem Strich wahrscheinlich beides gleich kompiliert / geparst.
Es geht ja nicht nur darum den Code kürzer zu halten,
sondern auch darum, dass er schneller ist.
Wenn ich eine Forschleife durch gehe und dann das return nicht in der selben habe
und das gesuchte Element bei 100 von 100.000 (order gar 1.000.000) ist,
macht das enorm was aus,
das gleiche bei break;.
Beitrag zuletzt geändert: 18.3.2011 8:47:59 von sneppa -
pantherstyle schrieb:
andererseits kann hierüber eine Differenzierung stattfinden, wodurch weiterer redundanter Code übersprungen werden kann (Falls das Object == null ist z.B.).
Das lässt sich aber besser und sauberer über das kleine Wörtchen else realisieren.
pantherstyle schrieb:
Allgemein lässt sich zusammenfassen, wenn dieses Verhalten nicht erwünscht wäre, dann hätten es doch kaum so viele Programmiersprachen als valides Verhalten zugelassen ^^
Es gibt durchaus Situationen, wo dieses Verhalten sinnvoll ist und sogar zur übersichtlichkeit des Codes beitragen kann. Es macht Sinn, dass dieses Verhalten da ist. Das heisst aber nicht, dass man es immer benutzen sollte, wenn es möglich ist.
misc schrieb:
Bei so einem kurzen Code ist das absolut überflüssig und generiert häufig mehr Zeilen. Wie bereits gesagt ist es verständlicherweise umstritten - schlussendlich muss man selbst (oder in grossen Projekten die Beteiligten) den Code verstehen. Genauso gut könnte man "break" vermeiden, es ist jedoch ebenfalls ein sehr vereinfachendes Element das einige Zeilen Code sparen kann. Ausserdem wird unter dem Strich wahrscheinlich beides gleich kompiliert / geparst.
Auch break ist ein Befehl, mit dem man sparsam umgehen sollte. Und gerade bei so kurzem Code ist es auch einfach, auf überflüssige returns zu verzichten. Und ich habe während meiner Arbeit schon häufig Code gesehen, der unsauber geschrieben wurde weil "es ja nur ein Dreizeiler ist". Der dann "mal eben" an neue Funktionalitäten angepasst wurde oder um ein paar Zeilen erweitert wurde und später dann zu einer riesigen und unübersichtlichen Bugquelle wurde.
Wie gesagt, es gibt Stellen, da macht eine Verwendung von return (und auch break) Sinn um eine Funktion oder eine Schleife zu beenden. Aber man sollte sich immer fragen, ob es nicht auch anders geht. Und Zeilen sparen ist meistens kein wirklich gutes Argument.
sneppa schrieb:
Wenn ich eine Forschleife durch gehe und dann das return nicht in der selben habe
und das gesuchte Element bei 100 von 100.000 (order gar 1.000.000) ist,
macht das enorm was aus,
das gleiche bei break;.
Kann man auch genausogut (und sauberer) über eine Variable steuern.
$resume = true; for ($i=1 ; $resume && ($i <= 10000000000000000000); $i++) { if ($i == 100) { //do something $resume = false; } }
Macht bei einer einfachen Schleife weder vom Arbeitsaufwand noch von der Übersichtlichkeit einen großen Unterschied, aber wennd ie Strukturen komplexer werden lassen sich Schleifen so sehr viel besser steuern.
PS. Da das Thema gerade ziemlich offtopic wird sollte die Diskussion evtl. in einem eigenen Thread weitergeführt werden. Gibts die Möglichkeit, dass ein Mod den Offtopicteil abspltet?
Beitrag zuletzt geändert: 18.3.2011 9:12:33 von digital-diceland -
digital-diceland schrieb:
Kann man auch genausogut (und sauberer) über eine Variable steuern.
$resume = true; for ($i=1 ; $resume && ($i <= 10000000000000000000); $i++) { if ($i == 100) { //do something $resume = false; } }
Das ist für dich sauberer?
Ich habe eben einen kleinen Test mit Microtime-Messung gemacht:
Deine Variante:
0.00131106376648 s
Meine Variante:
0.000982046127319 s
Deine Variante war in diesem Fall:
$resume = true; for ($i=1 ; $resume && ($i <= 10000000000000000000); $i++) { if ($i == 10000) { //do something $resume = false; } }
Meine Variante war in diesem Fall:
for ($i=1 ; $i <= 10000000000000000000; $i++) { if ($i == 10000) { break; } }
Finde, dass das schon ein Unterschied macht..
Würde man den Test mit $i == 100000000 machen:
Deine:
12.5293061733 s
Meine:
10.0004110336 s
Beitrag zuletzt geändert: 18.3.2011 9:21:27 von sneppa -
Ich habe die selbe Sache einmal mit Java und C# ausprobiert und komme auf ein ähnliches Ergebnis wie sneppa (natürlich mit anderen Zeitwerten aber dem selben Endergebnis). Zudem müsste man für tiefgreifendere nicht polemische Diskussionen hierzu erstmal definieren was als übersichtlicher gilt. Für mich sind beispielsweise weniger Zeilen meistens übersichtlicher. Für Andere mag hier eine eindeutige Variablenzuweisung oder separierte Schnittstellen mehr wiegen.
-
Ja, das bezeichne ich als sauberer. Einen sehr wichtigen Teil der Schleife hast du nämlich weggelassen. Den, den ich kurz mit
dargestellt habe und der die eigentliche Arbeitszeit der meisten Schleifen darstellt.Bei einer Schleife, die nichts macht, als auf ihre Abbruchbedingung zu warten ist es idiotisch überhaupt eine for-Schleife zu bauen. Abgesehen davon bedeutet sauberer Code nicht, dass er schneller ist, sondern, dass er besser zu warten und zu erweitern ist. Das bedeutet, dass er übersichtlich sein muss und (um diesen Punkt auch zu klären) das verstehe ich so, dass der Code möglichst von einem beliebigen Entwickler möglichst schnell in seiner Gesammtheit verstanden werden kann, selbst wenn er nicht mehr funktioniert.//do something
-
Scheint definitiv eine persönliche Ansichtssache zu sein,
die Leserlichkeit eines Quellcodes sollte wohl weniger an einem return liegen,
als viel mehr an einem logischen Aufbau der Klassen.
Ich verbinde auch Schnelligkeit nicht mit sauberem Code,
aber ich glaube, dass man sich über das Thema wohl tagelang die Köpfe einschlagen könnte,
da jeder seine gewissen persönliche Vorzüge hat ;) -
digital-diceland schrieb:
[...]
Kann man auch genausogut (und sauberer) über eine Variable steuern.
[...]$resume = true; for ($i=1 ; $resume && ($i <= 10000000000000000000); $i++) { if ($i == 100) { //do something $resume = false; } }
Meiner Meinung nach ist diese Verwendung einer FOR-Schleife nicht sauberer. Die Semantik einer FOR-Schleife sagt aus, dass über einen Container (beispielsweise ein Array) iteriert wird, solange der Index zum Beispiel kleiner oder kleiner gleich der Anzahl der Elemente ist.
Wenn im Schleifenkopf mehrere Ausdrücke ausgewertet werden sollten, würde ich eine WHILE-Schleife verwenden:
$i=1; $resume=true; while ($resume && $i <= 10000000000000000000) { if ($i == 100000) { $resume = false; } $i++; }
In meiner deterministischen Erhebung ist die Performance der WHILE-Schleife ähnlich, wenn nicht sogar besser, als die der FOR-Schleife mit dem BREAK. Ein Break sollte in der Tat sparsam verwendet werden, wie auch digital-diceland bereits geschrieben hat, denn dieser Meinung bin ich auch.
digital-diceland schrieb:
[...]
Auch break ist ein Befehl, mit dem man sparsam umgehen sollte. Und gerade bei so kurzem Code ist es auch einfach, auf überflüssige returns zu verzichten. Und ich habe während meiner Arbeit schon häufig Code gesehen, der unsauber geschrieben wurde weil "es ja nur ein Dreizeiler ist". Der dann "mal eben" an neue Funktionalitäten angepasst wurde oder um ein paar Zeilen erweitert wurde und später dann zu einer riesigen und unübersichtlichen Bugquelle wurde.
Wie gesagt, es gibt Stellen, da macht eine Verwendung von return (und auch break) Sinn um eine Funktion oder eine Schleife zu beenden. Aber man sollte sich immer fragen, ob es nicht auch anders geht. Und Zeilen sparen ist meistens kein wirklich gutes Argument.
[...]
sneppa schrieb:
[...]Ich verbinde auch Schnelligkeit nicht mit sauberem Code,[...]
Vielleicht können mit der WHILE-Schleife Schnelligkeit und Lesbarkeit zumindest etwas vereint werden.
Beitrag zuletzt geändert: 28.3.2011 6:46:00 von wagnerm -
wagnerm schrieb:
Meiner Meinung nach ist diese Verwendung einer FOR-Schleife nicht sauberer. Die Semantik einer FOR-Schleife sagt aus, dass über einen Container (beispielsweise ein Array) iteriert wird, solange der Index zum Beispiel kleiner oder kleiner gleich der Anzahl der Elemente ist.
Wenn im Schleifenkopf mehrere Ausdrücke ausgewertet werden sollten, würde ich eine WHILE-Schleife verwenden:
Hast du völlig recht. Das Optimum für den Fall ist eine while. -
Diskutiere mit und stelle Fragen: Jetzt kostenlos anmelden!
lima-city: Gratis werbefreier Webspace für deine eigene Homepage