rekursion... Perl verweigert den Dienst...
Markus
- perl
0 der heinrich0 Markus
ich habe eine script zum erzeugen einer Baumstruktur geschrieben...
das funktioniert auch super, bis zur 16. rekursion, ist das in Perl irgenwo festgelegt, wie oft eine subroutine verschachtelt aufgerufen werden darf?
Wäre schön wenn irgendjemand was zu dem Thema sagen könnte!
mFG Markus
hi markus!
nein, perl schränkt hier meines wissens nach in keiner weise ein.
die frage ist ja, ob du deine routine wirklich 16x in sich selbst verschachteln musst?
ein stück code ist hier wohl unabdingbar...
hi markus!
nein, perl schränkt hier meines wissens nach in keiner weise ein.
die frage ist ja, ob du deine routine wirklich 16x in sich selbst verschachteln musst?
ein stück code ist hier wohl unabdingbar...
OK
Die Datenbanktstruktur sieht wie folgt aus:
+-------+--------+-------+--------+
| ID | name | layer | parent |
+-------+--------+-------+--------+
| 1 | Home | 0 | 1 |
| 2 | test1 | 1 | 1 |
. . . .
. . . .
. . . .
| 38086 | test2 | 1 | 1 |
| 38087 | blabla | 2 | 1 |
+-------+--------+-------+--------+
das script wie folgt:
sub checkchild {
my $tree;
my @vars = sql(qq{
SELECT * FROM ebay_categories
WHERE parent = '$_[0]' AND ID != parent});
my $count = (@vars/4);
if ($count > 0)
{
for (my $c = 0; $c < $count; $c++)
{
my $layer = "";
while ($vars[2+$c*4] >= 0)
{
$layer.=" ";
$vars[2+$c*4]--;
if ($vars[2+$c*4] == 0)
{
$layer.="»";
}
}
$tree.="$layer<a href="#">$vars[1+$c*4]</a><br>\n";
$tree.=checkchild($vars[0+$c*4]);
}
}
return($tree);
}
print checkchild('1');
vielleicht sieht ja nun jemand, was ich 'falsch' mache...
Gruß, Markus
Da fehlt eine maskierung \ vor dem " beim link <a href="#">,
die bitte dazu denken!
P.S.: das ganze läuft auch gut mit tabellen die nicht grade 38000 Datensätze enthalten, sondern nur 50 oder so...
mfG Markus
Die Datenbanktstruktur sieht wie folgt aus:
+-------+--------+-------+--------+
| ID | name | layer | parent |
+-------+--------+-------+--------+
| 1 | Home | 0 | 1 |
| 2 | test1 | 1 | 1 |
. . . .
. . . .
. . . .
| 38086 | test2 | 1 | 1 |
| 38087 | blabla | 2 | 1 |
+-------+--------+-------+--------+das script wie folgt:
sub checkchild {
my $tree;
my @vars = sql(qq{
SELECT * FROM ebay_categories
WHERE parent = '$_[0]' AND ID != parent});
Für mich sieht es so aus, als ob di hier alle Datensätzemit der parent ID $_[0] abfragst.
my $count = (@vars/4);
Also hier die Anzahl der Datnesätze durch 4.
if ($count > 0)
$count ist immer größer null, solange in @vars ein Wert steht, es ist wohl sinnvoller direkt auf @vars oder $vars[0] zuz prüfen.
{
for (my $c = 0; $c < $count; $c++)
{
my $layer = "";
while ($vars[2+$c*4] >= 0)
und hier hört'es auf. Plötzlich ist $vars[..] kein Datensatz sondern ein Wert ungleich null, was ergibt denn oben deine sql Abfrage? Nicht die Datensätze?
{
$layer.=" ";
$vars[2+$c*4]--;
if ($vars[2+$c*4] == 0)
Mir scheint es, du willst irgendwelche einfachen Zusmamenhänge in deiner DB ergründen, diese machst du aber extrem Umständlich und Zeitintensiv (Du überträgst wahrscheinlich die komplette DB mit allen 38.000 Einträgen von deinem DB server)
{
$layer.="»";
}
}
$tree.="$layer<a href="#">$vars[1+$c*4]</a><br>\n";
Warum du einen Link benutzt ohne eine URL ist natürlich auch nocht ein Rätsel.
$tree.=checkchild($vars[0+$c*4]);
}
}
return($tree);
}print checkchild('1');
vielleicht sieht ja nun jemand, was ich 'falsch' mache...
so ganz verstehe ich nicht was du wirklich machen willst, da es nicht ersichtlich ist, was in @vars steht. Unter Umständen ist das ganze viel einfacher über eine sinnvolle SQL Abfrage zu lösen.
Struppi.
Die Datenbanktstruktur sieht wie folgt aus:
+-------+--------+-------+--------+
| ID | name | layer | parent |
+-------+--------+-------+--------+
| 1 | Home | 0 | 1 |
| 2 | test1 | 1 | 1 |
. . . .
. . . .
. . . .
| 38086 | test2 | 1 | 1 |
| 38087 | blabla | 2 | 1 |
+-------+--------+-------+--------+das script wie folgt:
sub checkchild {
my $tree;
my @vars = sql(qq{
SELECT * FROM ebay_categories
WHERE parent = '$_[0]' AND ID != parent});Für mich sieht es so aus, als ob di hier alle Datensätzemit der parent ID $_[0] abfragst.
Ganz genau! außer dem der selbst parent ist...
my $count = (@vars/4);
Also hier die Anzahl der Datnesätze durch 4.
Das bringt die &sql funktion so mit, die liefert ein array der ergebnismenge, also pro datensatz 4 einträge im array, /4 = anzahl der datensätze
if ($count > 0)
$count ist immer größer null, solange in @vars ein Wert steht, es ist wohl sinnvoller direkt auf @vars oder $vars[0] zuz prüfen.
ok, kann man machen, geb ich dir recht
{
for (my $c = 0; $c < $count; $c++)
{
my $layer = "";
while ($vars[2+$c*4] >= 0)und hier hört'es auf. Plötzlich ist $vars[..] kein Datensatz sondern ein Wert ungleich null, was ergibt denn oben deine sql Abfrage? Nicht die Datensätze?
Vergiss die while schleife, die malt nur entsprechend dem Layer, bzw. der Eintragstiefe leerzeichen und ein » in den skalar $layer
{
$layer.=" ";
$vars[2+$c*4]--;
if ($vars[2+$c*4] == 0)Mir scheint es, du willst irgendwelche einfachen Zusmamenhänge in deiner DB ergründen, diese machst du aber extrem Umständlich und Zeitintensiv (Du überträgst wahrscheinlich die komplette DB mit allen 38.000 Einträgen von deinem DB server)
{
$layer.="»";
}
}
$tree.="$layer<a href="#">$vars[1+$c*4]</a><br>\n";Warum du einen Link benutzt ohne eine URL ist natürlich auch nocht ein Rätsel.
weil ich den link hier nich veröffentlichen wollte hab ich ihn durch # ersetzt
$tree.=checkchild($vars[0+$c*4]);
}
}
return($tree);
}print checkchild('1');
vielleicht sieht ja nun jemand, was ich 'falsch' mache...
so ganz verstehe ich nicht was du wirklich machen willst, da es nicht ersichtlich ist, was in @vars steht. Unter Umständen ist das ganze viel einfacher über eine sinnvolle SQL Abfrage zu lösen.
jetzt besser?
Struppi.
Markus
sub checkchild {
my $tree;
my @vars = sql(qq{
SELECT * FROM ebay_categories
WHERE parent = '$_[0]' AND ID != parent});Für mich sieht es so aus, als ob di hier alle Datensätzemit der parent ID $_[0] abfragst.
Ganz genau! außer dem der selbst parent ist...
und dazu brauchst du eine Rekursive Funktion?
Ist das nicht das Gleiche wie:
my @vars = sql(qq{
SELECT * FROM ebay_categories
WHERE ID != parent SORT BY parent});
my $count = (@vars/4);
Also hier die Anzahl der Datnesätze durch 4.
Das bringt die &sql funktion so mit, die liefert ein array der ergebnismenge, also pro datensatz 4 einträge im array, /4 = anzahl der datensätze
Benutzt du nicht das DBI Modul?
Struppi.
sub checkchild {
my $tree;
my @vars = sql(qq{
SELECT * FROM ebay_categories
WHERE parent = '$_[0]' AND ID != parent});Für mich sieht es so aus, als ob di hier alle Datensätzemit der parent ID $_[0] abfragst.
Ganz genau! außer dem der selbst parent ist...und dazu brauchst du eine Rekursive Funktion?
Ist das nicht das Gleiche wie:
my @vars = sql(qq{
SELECT * FROM ebay_categories
WHERE ID != parent SORT BY parent});
Nein
SELECT * FROM ebay_categories WHERE ID != parent SORT BY parent
Nein diese abfrage gibt alle einträge außer die parents zurück
also ca. 86000
Diese
SELECT * FROM ebay_categories WHERE parent = '$_[0]' AND ID != parent});
gibt nur die entsprechenden childs von $_[0] zurück...
das sind so zwischen 0 und 30 Datensätze
my $count = (@vars/4);
Also hier die Anzahl der Datnesätze durch 4.
Das bringt die &sql funktion so mit, die liefert ein array der ergebnismenge, also pro datensatz 4 einträge im array, /4 = anzahl der datensätzeBenutzt Du nicht das DBI Modul?
Doch klar, in der sql subroutine
Struppi.
Markus
Ist das nicht das Gleiche wie:
my @vars = sql(qq{
SELECT * FROM ebay_categories
WHERE ID != parent SORT BY parent});
Nein
SELECT * FROM ebay_categories WHERE ID != parent SORT BY parent
Nein diese abfrage gibt alle einträge außer die parents zurück
also ca. 86000Diese
SELECT * FROM ebay_categories WHERE parent = '$_[0]' AND ID != parent});
gibt nur die entsprechenden childs von $_[0] zurück...
das sind so zwischen 0 und 30 Datensätze
und wozu die Rekursion?
my $count = (@vars/4);
Also hier die Anzahl der Datnesätze durch 4.
Das bringt die &sql funktion so mit, die liefert ein array der ergebnismenge, also pro datensatz 4 einträge im array, /4 = anzahl der datensätzeBenutzt Du nicht das DBI Modul?
Doch klar, in der sql subroutine
Aber was ist das für eine seltsame Struktur?
Du liest die komepltten Daten ein und erzeugst dann Array in dem jeweils 4 Einträge einem Datensatz entsprechen?
Warum nicht
$vars = [
[satz_1_feld_1, satz_1_feld_2, satz_1_feld_3, satz_1_feld_4],
[satz_2_feld_1, satz_2_feld_2, satz_2_feld_3, satz_2_feld_4]
];
also eine Struktur die auch den Daten entspricht? Oder die von der DBI Abfrage zurück kommt (ich nehme an du nimmst fetchrow_arrayref)
Struppi.
und wozu die Rekursion?
um die Baumstruktur zu erzeugen
nochmal:
ich hole Datum 1 aus der Datenbank,
dann rufe ich die Funktion erneut auf um --+
alle Kinder von Datum1 zu ermitteln } Rekursion bis +
dann rufe ich die Funktion erneut auf um --+ |
alle Kinder von Kindern zu ermitteln |
|
+-------------------------------------------------------------+
|
+---> @vars true ist, also solange ein ergebnis geliefert wird
Das ganze möchte ich dann als Baum anzeigen... etwa wie im Windows explorer die Dateileiste
Das ganze funktionier wie gesagt auch, jedenfalls mit meinen testdateien
Aber was ist das für eine seltsame Struktur?
Du liest die komepltten Daten ein und erzeugst dann Array in dem jeweils 4 Einträge einem Datensatz entsprechen?Warum nicht
$vars = [
[satz_1_feld_1, satz_1_feld_2, satz_1_feld_3, satz_1_feld_4],
[satz_2_feld_1, satz_2_feld_2, satz_2_feld_3, satz_2_feld_4]
];also eine Struktur die auch den Daten entspricht? Oder die von der DBI Abfrage zurück kommt (ich nehme an du nimmst fetchrow_arrayref)
Das ist historisch gewachsen :)
Struppi.
Tag Markus.
Benutzt Du nicht das DBI Modul?
Doch klar, in der sql subroutine
Warum lässt du deine Subroutine nicht einfach 0 zurückliefern, wenn es keine Ergebnisse gibt, dann sollte sich der rekursive Aufruf der Funktion auch besser steuern lassen. Und eventuell solltest du mit Referenzen arbeiten, das könnte effizienter sein:
sub abfrage {
my $statement = shift;
my $sth = $dbh->prepare($statement);
$sth->execute();
my $rows = $sth->rows;
if ($rows <= 0) {
return 0;
}
else {
my @rows = $sth->fetchrow_array();
return \@rows;
}
}
my $ret = abfrage(...);
if($ret) {
# tu was
# neuer Aufruf von abfrage
}
Ungetestet runtergetippt, Fehler bitte ich nachzusehen.
Siechfred
'Ungetestet runtergetippt' entspricht so ziemlich meiner subroutine sql,
nur dass diese nicht 0 zurückgibt...
werd ich mal einbauen
thx, markus
Moin!
Die Datenbanktstruktur sieht wie folgt aus:
+-------+--------+-------+--------+
| ID | name | layer | parent |
+-------+--------+-------+--------+
| 1 | Home | 0 | 1 |
| 2 | test1 | 1 | 1 |
. . . .
. . . .
. . . .
| 38086 | test2 | 1 | 1 |
| 38087 | blabla | 2 | 1 |
+-------+--------+-------+--------+my @vars = sql(qq{
SELECT * FROM ebay_categories
WHERE parent = '$_[0]' AND ID != parent});
my $count = (@vars/4);
SELECT * ist ja grundsätzlich böse - in diesem Fall aber nochmal extraböse!
Denn du verläßt dich drauf, dass dein * im SELECT immer genau 4 Spalten auswirft. Änderst du irgendwann in der Datenbank die Struktur, dann hast du hier in deinem Code ganz böse viele Anpassungsprobleme, weil du nicht mehr durch 4 teilen mußt, sondern durch die neue Anzahl von Spalten, die in der DB stecken.
Generell finde ich das gewählte Datenformat für die Speicherung der Datensätze sehr unglücklich. Ein zweidimensionales Array wäre wesentlich angemessener gewesen, eventuell auch eine Kombination aus Array und Hash (um auf die Spalten der Datenbank zuzugreifen - der Code wird wesentlich verständlicher).
Das Problem ist auch, dass die Zahl 4 nicht als veränderbare Konstante definiert ist, sondern als Zahl an allen möglichen Stellen vorkommt - eventuell auch dort, wo "4" nicht die Zahl der Spalten aus dem SQL-Statement meint. Spätere Änderungen sind also durchaus problematisch.
Ich gebe zu, dass das alles mit deinem Hauptproblem wenig zu tun hat, aber es ist IMO eine Frage des grundsätzlichen Stils, den man durchaus mal diskutieren sollte. Ab einem gewissen Kenntnislevel kann man sich im Programmieren eben nur noch im Stil verbessern. :)
- Sven Rautenberg
Moin!
Tach Sven!
Die Datenbanktstruktur sieht wie folgt aus:
+-------+--------+-------+--------+
| ID | name | layer | parent |
+-------+--------+-------+--------+
| 1 | Home | 0 | 1 |
| 2 | test1 | 1 | 1 |
. . . .
. . . .
. . . .
| 38086 | test2 | 1 | 1 |
| 38087 | blabla | 2 | 1 |
+-------+--------+-------+--------+my @vars = sql(qq{
SELECT * FROM ebay_categories
WHERE parent = '$_[0]' AND ID != parent});
my $count = (@vars/4);SELECT * ist ja grundsätzlich böse - in diesem Fall aber nochmal extraböse!
Denn du verläßt dich drauf, dass dein * im SELECT immer genau 4 Spalten auswirft. Änderst du irgendwann in der Datenbank die Struktur, dann hast du hier in deinem Code ganz böse viele Anpassungsprobleme, weil du nicht mehr durch 4 teilen mußt, sondern durch die neue Anzahl von Spalten, die in der DB stecken.
Generell finde ich das gewählte Datenformat für die Speicherung der Datensätze sehr unglücklich. Ein zweidimensionales Array wäre wesentlich angemessener gewesen, eventuell auch eine Kombination aus Array und Hash (um auf die Spalten der Datenbank zuzugreifen - der Code wird wesentlich verständlicher).
Ja, dazu muß ich Dir auf jeden Fall recht geben!
ich habe mal (irgendwann früher :-))diese unterfunktion sql geschrieben, um mir den Zugriff auf die Datenbank zu vereinfachen.
so kann ich halt einfach scalar = sql($datenbankabfrage) aufrufen und die gewünschten Daten sind im array... man ist ja schreibfaul.
Sicher ist es nicht grade glücklich, das geb ich gern zu :) und ich werde das auch bestimmt demnächst mal ändern, weil's mir teils selbst auf den Sack geht... aber hier ist nochmals zu erwähnen :man ist ja faul
Das Problem ist auch, dass die Zahl 4 nicht als veränderbare Konstante definiert ist, sondern als Zahl an allen möglichen Stellen vorkommt - eventuell auch dort, wo "4" nicht die Zahl der Spalten aus dem SQL-Statement meint. Spätere Änderungen sind also durchaus problematisch.
Da stimme ich zu!
Ich gebe zu, dass das alles mit deinem Hauptproblem wenig zu tun hat, aber es ist IMO eine Frage des grundsätzlichen Stils, den man durchaus mal diskutieren sollte. Ab einem gewissen Kenntnislevel kann man sich im Programmieren eben nur noch im Stil verbessern. :)
Das ist nicht schlimm, ich hab das script nochmal durchgesehen, einige varialblenzuweisungen in schleifen vorgenommen, sodass sie beim rekursionsaufruf nicht überschrieben werden, und schon ging alles :)
Einziges was ich noch suboptimal halte ist, dass das script 54sek braucht um die 86000+ Datensätze als Baum "aufzumalen"
Aber irgendwo bekomm ich's nicht optimaler hin... Das mag evtl. daran liegen, dass ich als Dachdeckermeister nicht soviel kenne von sowas hab :)
- Sven Rautenberg
Gruß, Markus
Moin!
Einziges was ich noch suboptimal halte ist, dass das script 54sek braucht um die 86000+ Datensätze als Baum "aufzumalen"
Das dürfte höchstwahrscheinlich an der Rekursion liegen.
Jedes rekursiv lösbare Problem läßt sich auch iterativ lösen. Und in allen Fällen des "Baumwesens" würde ich dringend empfehlen, die Datenbank genau EINMAL nach ALLEN in Frage kommenden Datensätzen zu befragen, und den Aufbau der Baumstruktur dann im RAM-Speicher zu sortieren.
Wobei die Sache dann auch noch dadurch beschleunigt werden kann, dass du die Inhalte der Datenbank nicht nochmal kopierst, sondern mit Zeigern oder Referenzen arbeitest.
Aber irgendwo bekomm ich's nicht optimaler hin... Das mag evtl. daran liegen, dass ich als Dachdeckermeister nicht soviel kenne von sowas hab :)
Das ist keine akzeptable Ausrede.
- Sven Rautenberg
Hi,
Aber irgendwo bekomm ich's nicht optimaler hin...
Das kann ja schon aus prinzipiellen Gründen nicht gehen.
cu,
Andreas