Ankündigung

Einklappen
Keine Ankündigung bisher.

Ist diese Rekursion O.K.?

Einklappen

Neue Werbung 2019

Einklappen
X
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • Ist diese Rekursion O.K.?

    Hi

    Das Array locs lese ich aus einer Datenbank aus. Aufmerksam gelesen,
    steht da z. B. drin, dass WestEurope, Austria, Belgium, Iberia, Spain, Portugal, UknIreland, UK, Ireland zu einem Familienzweig gehören.

    Nun möchte ich bei Vorgabe irgendeiner Location, den ganzen Rattenschwanz von Kindern und Kindeskindern in ein Ergebnis-Array schreiben. Z. B. hängt Iberia an WestEurope dran und Spain, Portugal wiederum an Iberia.

    Das scheint mit mit anhängendem Code gelungen zu sein. Da ich allerdings ein absoluter Rekursionsidiot bin würde ich die Vollblutprogrammierer unter Euch fragen wollen, ob die Lösung Macken hat oder viel eleganter geht.

    PHP-Code:
    $locs[1]['name'] = "Europe"
    $locs[1]['parent'] = 0;
    $locs[2]['name'] = "WestEurope"
    $locs[2]['parent'] = 1;
    $locs[3]['name'] = "EastEurope"
    $locs[3]['parent'] = 1;
    $locs[4]['name'] = "Austria"
    $locs[4]['parent'] = 2;
    $locs[5]['name'] = "Poland"
    $locs[5]['parent'] = 3;
    $locs[6]['name'] = "Belgium"
    $locs[6]['parent'] = 2;
    $locs[7]['name'] = "Croatia"
    $locs[7]['parent'] = 3;
    $locs[8]['name'] = "Iberia"
    $locs[8]['parent'] = 2;
    $locs[9]['name'] = "Spain"
    $locs[9]['parent'] = 8;
    $locs[10]['name'] = "Portugal"
    $locs[10]['parent'] = 8;
    $locs[11]['name'] = "UKnIrland"
    $locs[11]['parent'] = 2;
    $locs[12]['name'] = "UK"
    $locs[12]['parent'] = 11;
    $locs[13]['name'] = "Ireland"
    $locs[13]['parent'] = 11;
    $parents = array();
    //Hat eine Location einen parent-Wert > 0, dann gehört der parent-Wert ins Array aller Parents 
    foreach ($locs as $key => $loc) {
        if (
    $loc['parent'] > 0) {
            
    $parents[] = $loc['parent'];
        }
    }
    //Entferne Mehrfachnennungen
    $parents array_unique($parents);
    //Ein globales Ergebnis-Array
    $result_array = array();
    function 
    get_children_incl_parent($id,$locations,$parents){
        global 
    $result_array;
       
    //Eltern sollen im Ergebnis enthalten sein
       
    $result_array[] = $id;
       foreach(
    $locations as $key => $loc) {
            if (
    $loc['parent'] == $id) {
                
    //Prüfe, ob erfasstes Kind selber Kinder hat und erfasse diese auch. Rekursion ?!
                
    if (in_array($key,$parents)) {
                
    get_children_incl_parent($key,$locations,$parents);
                } else {
                
    //Ist Location direkt Kind => ins result_array schreiben
                
    $result_array[] = $key;
                }
                
            }
       } 
    }
    get_children_incl_parent(2,$locs,$parents);
    print_r($result_array); 
    Es ist schon alles gesagt. Nur noch nicht von allen.


  • #2
    Hallo,

    global ist schlecht. Wenn du eine Variable in einer Funktion benutzen möchtest, übergib sie per Parameter. Rekursionsergebnisse abgreifen kannst du dann auf unterschiedliche Weisen:

    PHP-Code:
    <?php
    function getParents1($childId, array $list$result = array())
    {
        if (!isset(
    $list[$childId]["parent"])) {
            return 
    $result;
        }
        
    $parentId $list[$childId]["parent"];
        if (!isset(
    $list[$parentId])) {
            return 
    $result;
        }
        
    $result[$parentId] = $list[$parentId];   
        return 
    getParents1($parentId$list$result);
    }
    function 
    getParents2($childId, array $list)
    {
        if (!isset(
    $list[$childId]["parent"])) {
            return array();   
        }
        
    $parentId $list[$childId]["parent"];
        if (!isset(
    $list[$parentId])) {
            return array();
        }
        return 
    array_merge(array($parentId => $list[$parentId]), getParents2($parentId$list));
    }

    echo 
    "<pre>";
    var_dump(getParents1(13$locs));
    echo 
    "</pre><hr /><pre>";
    var_dump(getParents2(13$locs));
    Dass der Schlüssel "parent" heißt ist eigentlich auch eine Implikation, die eine Funktion nicht zwingend vornehmen sollte. Das heißt auch das könnte man per Parameter übergeben:
    PHP-Code:
    <?php
    function getParents3($childId, array $list$key "parent"$result = array())
    {
        if (!isset(
    $list[$childId][$key])) {
            return 
    $result;
        }
        
    $parentId $list[$childId][$key];
        if (!isset(
    $list[$parentId])) {
            return 
    $result;
        }
        
    $result[$parentId] = $list[$parentId];   
        return 
    getParents3($parentId$list$key$result);
    }
    function 
    getParents4($childId, array $list$key "parent")
    {
        if (!isset(
    $list[$childId][$key])) {
            return array();   
        }
        
    $parentId $list[$childId][$key];
        if (!isset(
    $list[$parentId])) {
            return array();
        }
        return 
    array_merge(array($parentId => $list[$parentId]), getParents4($parentId$list$key));
    }
    ?>
    Problematisch wirds, wenn du einen Fehler in deiner Verlinkung hast, z.B. wenn Europe als Parent nun wieder Ireland stehen hat. Falls das bei dir der Fall sein könnte, kannst du mal diese Klasse ausprobieren:
    http://www.phpclasses.org/browse/file/26974.html
    Hatte ich vor einiger Zeit mal geschrieben um bei einem TreeView mit Aliasen zu verhindern, dass zirküläre Referenzen auftreten. Sprich C:/meinOrdner ist Alias von C:/, weil dann landest du eben in einer Endlosschleife beim Auslesen.


    Edit: Übrigens, parent = 0 ist ungünstig, da es nicht stimmt. NULL ist strikt genommen die bessere Wahl.
    "Mein Name ist Lohse, ich kaufe hier ein."

    Kommentar


    • #3
      Danke an Chriz

      Vielen Dank Chriz. Ich sehe schon, Rekursionen liegen Dir.
      Hast Du mein Script mal so wie angegeben ausgeführt?

      Das Ergebnis sieht dann richtigerweise so aus:

      Code:
      Array
      (
          [0] => 2
          [1] => 4
          [2] => 6
          [3] => 8
          [4] => 9
          [5] => 10
          [6] => 11
          [7] => 12
          [8] => 13
      )
      Das beantwortet die Frage Wie lauten die Ids (ArrayKeys) aller Lokationen, die zu West Europa gehören.

      Ich habe getParents1 und 3 mal auf mein Ausgangsarray angewandt. Das Ergebnis sieht dann so aus.

      Code:
      Array
      (
          [1] => Array
              (
                  [name] => Europe
                  [parent] => 0
              )
      )
      Statt eines globalen Arrays das Ergebnis per Parameter in der Rekursion zu übergeben hatte ich vorher versucht, hat aber (Stichwort:Rekursionsidiot) nicht geklappt. Irgendwie kamen da immer nur halbe Ergebnisse an.

      Edit: Übrigens, parent = 0 ist ungünstig, da es nicht stimmt. NULL ist strikt genommen die bessere Wahl.
      Die 0 steht in der Datenbank bei locationen die keine Eltern haben. Europa z.B. ist zu groß um noch geographische Eltern zu haben. Stimmt also doch.

      Ich würde gerne noch soweit kommen, tatsächlich mein Ergebnis in der Rekursion weiterzureichen statt ein globales Array einzusetzen. Ich werde meinen nächsten Versuch hier noch mal posten und hoffe auf Deine Hilfe.

      Gruß
      Es ist schon alles gesagt. Nur noch nicht von allen.

      Kommentar

      Lädt...
      X