Seite 1 von 2

rekursive Funktion umsortieren

Verfasst: 29.09.2013 01:11
von bluebull
Hallo. Ich bin beim Erstellen eines Stammbaumes. Dazu habe ich eine mySQL Datenbank, welche ich rekursiv Abfrage:

Code: Alles auswählen

//funktion vorfahren

function ahnen($id,$generation,$level)
{

        if($generation < 4)
       {
        $generation++;
        $sql = "SELECT * FROM personen WHERE id = '$id'";
        $result = mysql_query($sql);
        $person=mysql_fetch_array($result);
        $vater = $person['vater_id'];
        $mutter = $person['mutter_id'];
        echo str_repeat('&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp',$level)."$person[nachname] $person[vorname] *$person[geburtsdatum]<br>";
            {
            ahnen($vater,$generation,$level+1);
            ahnen($mutter,$generation,$level+1);

            }
        }

 }

 ahnen($id,0,0);
Die Ausgabe erfolgt im Schema

Code: Alles auswählen

aktuelle Person
   Vater
      Opa
         Ur-Opa
             etc.
         ur-Oma
      Oma
   Mutter
ich möchte aber:

Code: Alles auswählen

Ur-Opa + Ur-Oma
    Opa + Oma
        Vater + Mutter
            akteulle Person
Wie bekomme ich das hin?

Danke und Gruss

Re: rekursive Funktion umsortieren

Verfasst: 29.09.2013 01:42
von Nuramon
Wie genau ist denn deine Datenbank aufgebaut, also welche Spalten gibt es?
id, vater, mutter, nachname, vorname, geburtsdatum
oder sowas?

Und möchtest du sowohl Oma und Opa von Vater als auch Oma und Opa von Mutter ausgeben lassen?
Das wären noch wichtige Fragen.

Und sonst erst den Rekursiven Aufruf, dahinter die Ausgabe, und die Einrückung aus der Rückgabe der rekursiven Methode ziehen. Männlich/weiblich als boolean übergeben und an den Namen dann ein je nachdem ein + oder ein Linebreak anhängen.

Re: rekursive Funktion umsortieren

Verfasst: 29.09.2013 01:48
von cYbercOsmOnauT
Wie die DB aufgebaut ist, ist eher irrelevant. Es ist eine klassische Baum-Rekursion. Sein Ansatz ist schon richtig, nur darf man da nicht sofort ausgeben, sondern packt die Fünde sortiert in ein Array und gibt diesem am Ende aus wenn man den Baum komplett durch hat. Sind ja bei der Aufgabe gerade mal 14 Verästelungen.

Re: rekursive Funktion umsortieren

Verfasst: 29.09.2013 02:11
von bluebull
danke für die schnellen antworten. meine datenbank ist tatsächlich mit id, nachname, vorname, geburtsdatum, ..., vater_id, mutter_id aufgebaut.

es werden aber noch mehr generationen dazukommen und ich frage sowohl die vaterseite als auch die mutterseite soweit bekannt ab.

ich werde eure vorschläge mal ausprobieren (sofern ich das hinbekomme) und mich dann wieder melden. vielen dank

Re: rekursive Funktion umsortieren

Verfasst: 29.09.2013 04:06
von bluebull
Soweit so gut. Einige Sachen habe ich hinbekommen (manche nicht). Auch die Sortierung von unten nach oben stimmt nun.

Code: Alles auswählen

$id = '2';
$generationen = '12';

//Vorfahren funktion

function ahnen($id,$generation,$level)
{
global $generationen;
        if($generation < $generationen)
       {
        $generation++;
        $sql = "SELECT * FROM personen WHERE id = '$id'";
        $result = mysql_query($sql);
        $person=mysql_fetch_array($result);
        $vater = $person['vater_id'];
        $mutter = $person['mutter_id'];
            {
            ahnen($vater,$generation,$level+1);
            ahnen($mutter,$generation,$level+1);

            }

       echo str_repeat('&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp',$level)."$person[nachname] $person[vorname] *$person[geburtsdatum]<br>";
        }
 }

 ahnen($id,0,$generationen-1);
2 Probleme habe ich noch. Das eine ist, dass die "älteste Person" nun oben rechts ist (statt oben links) und das andere, dass ich exponentiel sternchen zwischen den Personen habe. Es schaut ungefähr so aus:

Code: Alles auswählen

                                                                                                                                    person *1640-00-00
                                                                                                                                    person  *0000-00-00
                                                                                                                              person  *0000-00-00
                                                                                                                                     *
                                                                                                                                     *
                                                                                                                              person  *0000-00-00
                                                                                                                        person  *0000-00-00
                                                                                                                                     *
                                                                                                                                     *
                                                                                                                               *
                                                                                                                                     *
                                                                                                                                     *
                                                                                                                               *
                                                                                                                        person  *0000-00-00
                                                                                                                  person  *1744-07-01
                                                                                                                                     *
                                                                                                                                     *
                                                                                                                               *
                                                                                                                                     *
                                                                                                                                     *
                                                                                                                               *
                                                                                                                         *
                                                                                                                                     *
                                                                                                                                     *
                                                                                                                   usw.
Leider bin ich noch sehr neu in PHP und mySQL und sehe den/die Fehler nicht. Ich danke euch für eure nette Hilfe.

Re: rekursive Funktion umsortieren

Verfasst: 29.09.2013 15:43
von Nuramon
Ich bin mal nett, hatte gerade das Bedürfnis, ein wenig an deinem Code rumzubasteln. Musste allerdings die Datenbankabfrage gegen ein Array austauschen zum Testen. Würde dir eh raten, lieber die Datenbank einmal auszulesen, in einem Array abzuspeichern, und damit zu arbeiten. Spart Abfragen an die Datenbank.

Mein Code sieht jetzt so aus:

Code: Alles auswählen

<?php

$id = 1;
$generationen = 12;

$personen = array(
    1 => array('name' => 'Person 1', 'vater_id' => 2, 'mutter_id' => 3),
    2 => array('name' => 'Vater 1', 'vater_id' => 4, 'mutter_id' => 5),
    3 => array('name' => 'Mutter 1', 'vater_id' => 6, 'mutter_id' => 7),
    4 => array('name' => 'Vater 2', 'vater_id' => 8, 'mutter_id' => 9),
    5 => array('name' => 'Mutter 2', 'vater_id' => 10, 'mutter_id' => 11),
    //6 => array('name' => 'Vater 2.2', 'vater_id' => 11, 'mutter_id' => 12),
    //7 => array('name' => 'Mutter 2.2', 'vater_id' => 12, 'mutter_id' => 13),
    );

//Vorfahren funktion

function ahnen($id, $generation, $is_vater)
{
    global $generationen, $personen;
    if($generation < $generationen)
    {
        $generation++;
        
        if(!isset($personen[$id]))
            return 0;
        //$sql = "SELECT * FROM personen WHERE id = '$id'";
        //$result = mysql_query($sql);
        //$person=mysql_fetch_array($result);
        $person = $personen[$id];
        $vater = $person['vater_id'];
        $mutter = $person['mutter_id'];
        {
            $level = ahnen($vater,$generation,true);
            ahnen($mutter,$generation,false);

        }

        if($is_vater)
            echo str_repeat('&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp',$level)."$person[name]";
        else
            echo '&nbsp+&nbsp' . "$person[name]<br>";
    }
    return $level + 1;
}

ahnen($id,0,true);

?>
Ausgabe ist:

Code: Alles auswählen

Vater 2 + Mutter 2
      Vater 1 + Mutter 1
            Person 1

Das Problem, was sich jetzt stellt, ist, wenn du den Stammbaum nicht nur in eine Richtung haben möchtest. Also wenn er etwa so aufgebaut sein soll:

Code: Alles auswählen

Vater 2 + Mutter 2          Vater 2.2 + Mutter 2.2
               Vater 1 + Mutter 1
                    Person 1
Kannst du bei meinem Code testen, indem du oben die beiden weiteren Array-Zeilen einkommentierst.
Das Problem hierbei ist einfach, dass du dann nicht sofort ausgeben darfst. Du musst gucken, wie viele parallel-Generationen existieren, und sie in eine Zeile zusammenbasteln, dann ausgeben.
Beste Lösung hier wäre wohl ein Array anzulegen über die Generationen und in denen die Leute in einem Array pro Generation einspeichern, statt sofort auszugeben. Allerdings besteht dann das Problem mit der Formatierung, die dann schwieriger wird, und was passiert, wenn ein Elternteil beispielweise keine Großeltern angegeben hat, eines aber schon.

Hoff aber die Grundidee ist klar?

Re: rekursive Funktion umsortieren

Verfasst: 29.09.2013 15:56
von Nuramon
Sorry für den Doppelpost, finde es aber unübersichtlich, das in einen zu hauen. Hab jetzt noch ein wenig geschraubt, dass es halbwegs geht. Schau mal hier

Code: Alles auswählen

<?php

$id = 1;
$generationen = 12;
$stammbaum = array();

$personen = array(
    1 => array('name' => 'Person 1', 'vater_id' => 2, 'mutter_id' => 3),
    2 => array('name' => 'Vater 1', 'vater_id' => 4, 'mutter_id' => 5),
    3 => array('name' => 'Mutter 1', 'vater_id' => 6, 'mutter_id' => 7),
    4 => array('name' => 'Vater 2', 'vater_id' => 8, 'mutter_id' => 9),
    5 => array('name' => 'Mutter 2', 'vater_id' => 10, 'mutter_id' => 11),
    6 => array('name' => 'Vater 2.2', 'vater_id' => 11, 'mutter_id' => 12),
    7 => array('name' => 'Mutter 2.2', 'vater_id' => 12, 'mutter_id' => 13),
    );

//Vorfahren funktion

function ahnen($id, $generation, $is_vater)
{
    global $generationen, $personen, $stammbaum;
    if($generation < $generationen)
    {
        $generation++;
        
        if(!isset($personen[$id]))
            return 0;
        //$sql = "SELECT * FROM personen WHERE id = '$id'";
        //$result = mysql_query($sql);
        //$person=mysql_fetch_array($result);
        $person = $personen[$id];
        $vater = $person['vater_id'];
        $mutter = $person['mutter_id'];
        {
            $level = ahnen($vater,$generation,true);
            ahnen($mutter,$generation,false);

        }

        if($is_vater)
        {
            $stammbaum[$generation][] = $person['name'];
        }
        else
        {
            $last_mother = $stammbaum[$generation][count($stammbaum[$generation])-1];
            $stammbaum[$generation][count($stammbaum[$generation])-1] = $last_mother . ' + ' . $person['name'];
        }
    }
    return $level + 1;
}

ahnen($id,0,true);

$row = 0;
foreach($stammbaum as $reihe)
{
    echo str_repeat('&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp',$row);
    foreach($reihe as $ahnenpaar)
    {
        echo $ahnenpaar . '&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp';
    }
    echo "<br />";
    $row = $row + 1;
}

?>
Ausgabe ist so:

Code: Alles auswählen

Vater 2 + Mutter 2      Vater 2.2 + Mutter 2.2      
                  Vater 1 + Mutter 1      
                                    Person 1      
Ich gebe es unten erst aus, sammel alles in der globalen Variable $stammbaum.
Hier müsstest du nur noch überarbeiten, dass leere Personen auch noch reingeschrieben werden, irgendwie, aber dann ohne +-Verknüpfung, da es sonst zu Formatierungsfehlern kommt. Musst da halt sowohl auf Vater als auch Mutter prüfen.
Oder stellst du sicher, dass der Baum vollständig ist? Dann würde es so gehen, wie es hier ist.
Formatierung sieht allerdings noch nicht so hübsch aus. Wird auch sehr schwierig. Da kommst du dann wohl nicht drumherum, Zeichen zu zählen und zu übergeben und darauf die exakten Abstände in Leerzeichen zu berechnen. Wird ein großer Aufwand, denke ich.

Re: rekursive Funktion umsortieren

Verfasst: 29.09.2013 19:49
von bluebull
Sehr cool. Danke. Ich werde den Code durcharbeiten und dan Rückmeldung geben.

Re: rekursive Funktion umsortieren

Verfasst: 03.10.2013 13:52
von bluebull
Hallo. Ja, die Darstellung war wirklich nicht optimal durchdacht. Ich habe mich jetzt für eine wesentlich einfachere Darstellung entschieden:

Code: Alles auswählen

vater ...
mutter ...
      vater des Vaters
      mutter des Vaters
            vater
      vater der mutter
      mutter der mutter
            mutter
                    aktuelle Person
                            ------------- andere abfrage---------------------
                            Kind 
                                Enkel
                            Kind
mein Code dazu

Code: Alles auswählen

//übergabe variablen
$id = 2;
$generationen = 12;

//darstellung

$spacer = '&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp';

//array

$query = mysql_query( "SELECT * FROM personen");
$personen = array();
while($row = mysql_fetch_assoc($query)){
    $personen []=$row;
}

//Vorfahren

function vorfahren($id,$generation,$level)
{
global $generationen, $spacer, $personen;
        if($generation < $generationen)
       {
        $generation++;
        $person = $personen[$id-1];
        $vater = $person['vater_id'];
        $mutter = $person['mutter_id'];

        if ($vater !== null){
        vorfahren($vater,$generation,$level-1);
        }
        if ($mutter !== null){
        vorfahren($mutter,$generation,$level-1);
        }
        echo str_repeat($spacer,$level)."$person[nachname] $person[vorname] *$person[geburtsdatum]\n<br>";
      }
 }
vorfahren($id,0,$generationen-1);

//aktuelle Person
$query = mysql_query("SELECT * FROM personen WHERE id = $id");
while($row = mysql_fetch_object($query))
         {
         echo str_repeat($spacer,$generationen-1)."<b>$row->nachname $row->vorname *$row->geburtsdatum</b>\n<br>";
         }

 
Wie kann ich die aktuelle Person in der Abfrage weglassen, damit ich diese durch eine separate Abfrage (wie im obigen Code) fett darstelen kann?

Re: rekursive Funktion umsortieren

Verfasst: 03.10.2013 20:29
von Miriam
So könnte es klappen:

Code: Alles auswählen

$personen = array();
$generation = 0;

//übergabe variablen
$id = 2;
$generationen = 12;

//darstellung
$spacer = '&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp';

//array
$query = mysql_query( "SELECT * FROM personen");


while($row = mysql_fetch_assoc($query))
{
    $personen[] = $row;
}

//Vorfahren
function vorfahren($id, $generation, $level)
{
    global $generationen, $spacer, $personen;

    if($generation < $generationen)
    {
        $generation++;
        $person = $personen[$id-1];
        $vater = $person['vater_id'];
        $mutter = $person['mutter_id'];

        if ($vater)
        {
            vorfahren($vater, $generation, $level-1);
        }
        if ($mutter)
        {
            vorfahren($mutter, $generation, $level-1);
        }
    }
    else
    {
        // aktuelle Person
        $person = $personen[$id];
        $level = $generationen;
    }
    echo str_repeat($spacer, $level) . "$person[nachname] $person[vorname] *$person[geburtsdatum]\n<br />";
}

vorfahren($id, $generation, $generationen-1); 
// Ungetestet