Wurmi: Array rekursiv nach oben ändern

Hallo!
Ich steh grad auf dem Schlauch...

Ich möchte eine Funktion schreiben, die wie bei einem Checkbox-Baum die Elternelemente abhängig von dem Wert der einzelnen Elemente ggf. anpasst, also in unten genanntem Beispiel

  • "Nordamerika" active=1 setzt (weil USA active=1),
  • "Amerika" active=1 setzt (weil USA active=1, bzw. dann Nordamerika active=1),
  • "Nicht-EU" active=1 setzt (weil Schweiz active=1),
  • "Europa" active=1 setzt (weil Schweiz active=1, bzw. dann Nicht-EU active=1)

Irgendwie muss das ja mit einer rekursiven Funktion lösbar sein, aber ich komme im Moment nicht drauf wie...

Jemand eine Idee?
Danke!

Andreas

Beispiel:

  
<?php  
$laender=array(  
	array("name"=>"Amerika", "active"=>0,  
        "children"=>array(  
            array("name"=>"Nordamerika", "active"=>0, "children"=>  
                array("name"=>"USA", "active"=>1),  
                array("name"=>"Kanada", "active"=>0)),  
            array("name"=>"Südamerika", "active"=>0, "children"=>  
                array("name"=>"Chile", "active"=>0),  
                array("name"=>"Argentinien", "active"=>0))  
        )  
	),  
	array("name"=>"Europa", "active"=>0,  
        "children"=>array(  
            array("name"=>"EU", "active"=>0,	"children"=>  
                array("name"=>"Deutschland", "active"=>0),  
                array("name"=>"Österreich", "active"=>0)),  
            array("name"=>"Nicht-EU", "active"=>0,	"children"=>  
                array("name"=>"Schweiz", "active"=>1)),  
        )  
	)  
);  
print_r($laender);  
?>  
  
Ausgabe von print_r():  
  
Array  
(  
    [0] => Array  
        (  
            [name] => Amerika  
            [active] => 0  
            [children] => Array  
                (  
                    [0] => Array  
                        (  
                            [name] => Nordamerika  
                            [active] => 0  
                            [children] => Array  
                                (  
                                    [name] => USA  
                                    [active] => 1  
                                )  
  
                            [0] => Array  
                                (  
                                    [name] => Kanada  
                                    [active] => 0  
                                )  
  
                        )  
  
                    [1] => Array  
                        (  
                            [name] => Südamerika  
                            [active] => 0  
                            [children] => Array  
                                (  
                                    [name] => Chile  
                                    [active] => 0  
                                )  
  
                            [0] => Array  
                                (  
                                    [name] => Argentinien  
                                    [active] => 0  
                                )  
  
                        )  
  
                )  
  
        )  
  
    [1] => Array  
        (  
            [name] => Europa  
            [active] => 0  
            [children] => Array  
                (  
                    [0] => Array  
                        (  
                            [name] => EU  
                            [active] => 0  
                            [children] => Array  
                                (  
                                    [name] => Deutschland  
                                    [active] => 0  
                                )  
  
                            [0] => Array  
                                (  
                                    [name] => Österreich  
                                    [active] => 0  
                                )  
  
                        )  
  
                    [1] => Array  
                        (  
                            [name] => Nicht-EU  
                            [active] => 0  
                            [children] => Array  
                                (  
                                    [name] => Schweiz  
                                    [active] => 1  
                                )  
  
                        )  
  
                )  
  
        )  
  
)  
  
Gewünschtes Ergebnis:  
  
<?php  
$laender_neu=array(  
	array("name"=>"Amerika", "active"=>1,  
        "children"=>array(  
            array("name"=>"Nordamerika", "active"=>1, "children"=>  
                array("name"=>"USA", "active"=>1),  
                array("name"=>"Kanada", "active"=>0)),  
            array("name"=>"Südamerika", "active"=>0, "children"=>  
                array("name"=>"Chile", "active"=>0),  
                array("name"=>"Argentinien", "active"=>0))  
        )  
	),  
	array("name"=>"Europa", "active"=>1,  
        "children"=>array(  
            array("name"=>"EU", "active"=>0,	"children"=>  
                array("name"=>"Deutschland", "active"=>0),  
                array("name"=>"Österreich", "active"=>0)),  
            array("name"=>"Nicht-EU", "active"=>1,	"children"=>  
                array("name"=>"Schweiz", "active"=>1)),  
        )  
	)  
);  
?>  

  1. Ist easy da du ja weißt wie weit es runter geht.
    Stze als einen Wert x auf 0, gehe dann komplett durch ob einer der active Werte auf 1 ist, wenn ja, setze x auf 1, wenn x===1 dann Setze active=1 beim ausgangsarray

    1. Danke, hättest Du da einen (Pseudo-)Code für mich?
      Das mit den Ländern ist nur ein Beispiel, im Idealfall sollte das Array beliebig verschachtelt sein können…

  2. Ich glaube dir bleibt nichts andere übrig als von oben nach unten anstatt umgekehrt durch zu laufen. Bekannte Struktur vorausgesetzt:
    funktion make_active_return_active ($array) {
     wenn (hat Kinder) dann {
      $dieses_aktiv = false;
      für jedes Kind tue {
       wenn (make_active_return_active(Kind)) dann {
        $dieses_aktiv = true;
       } //ende wenn
      } //ende foreach
     }//ende wenn
     return $dieses_aktiv
    }//ende function

    Wenn das Übergebene Array keine Kinder mehr hat wird einfach der "active"-Wert zurück gegeben. Wenn es Kinder hat wird der active-Wert erstmal false gesetzt und dann falls irgendein Kind active ist wird er wieder true gesetzt.
    Der so gewonnene Wert wird ebenfalls zurück gegeben.

    --
    sh:( fo:| ch:? rl:( br:& n4:& ie:{ mo:} va:) de:µ_de:] zu:) fl:( ss:| ls:[ js:(
    1. Das sieht ziemlich gut aus! :-)

      ich hab jetzt mal versucht, das so einigermaßen umzusetzen, aber es klappt noch nicht so ganz.
      Zwar gibt das Script korrekt aus, dass Amerika, Nordamerika, Europa und Nicht-EU active=1 werden soll, aber das Array selbst ändert sich nicht.

      Hier mal mein kompletter Code nochmal zum Testen.
      Kannst Du mir sagen, was daran noch falsch ist?

        
      <pre>  
      <?php  
      $laender=array(  
      	array("name"=>"Amerika", "active"=>0,  
              "children"=>array(  
                  array("name"=>"Nordamerika", "active"=>0,  
                      "children"=>array(  
                          array("name"=>"USA", "active"=>1),  
                          array("name"=>"Kanada", "active"=>0))  
                  ),  
                  array("name"=>"Südamerika", "active"=>0,  
                      "children"=>array(  
                          array("name"=>"Chile", "active"=>0),  
                          array("name"=>"Argentinien", "active"=>0)  
                      )  
                  )  
              )  
      	),  
      	array("name"=>"Europa", "active"=>0,  
              "children"=>array(  
                  array("name"=>"EU", "active"=>0,  
                      "children"=>array(  
                          array("name"=>"Deutschland", "active"=>0),  
                          array("name"=>"Österreich", "active"=>0)  
                      )  
                  ),  
                  array("name"=>"Nicht-EU", "active"=>0,  
                      "children"=>array(  
                          array("name"=>"Schweiz", "active"=>1)  
                      )  
                  )  
              )  
      	)  
      );  
      //print_r($laender);  
        
      make_active_return_active($laender);  
        
      function make_active_return_active (&$input) {  
          if(is_array($input['children'])){  
              foreach($input['children'] as $child){  
                  $test=make_active_return_active($child);  
                  if($test==1){  
                      echo $input['name']." ".$test."\n";  
                      $input['active'] = 1;  
                  }  
              }  
              return $input['active'];  
          }  
          elseif($input['active']){  
              return $input['active'];  
          }  
          elseif($input[0]['name']){  
              foreach($input as $child){  
                  make_active_return_active($child);  
              }  
          }  
      }  
        
      print_r($laender);  
      ?>  
      </pre>
      
      1. Zwar gibt das Script korrekt aus, dass Amerika, Nordamerika, Europa und Nicht-EU active=1 werden soll, aber das Array selbst ändert sich nicht.

        Hier mal mein kompletter Code nochmal zum Testen.
        Kannst Du mir sagen, was daran noch falsch ist?

        Ich vermute, dass entweder function oder foreach oder beide nicht direkt auf dem Array arbeiten, welches sie erhalten sondern auf einer Kopie. Ich kenne mich aber nicht ausreichend mit PHP-interna aus um das mit Bestimmtheit zu sagen.
        Aus dem Bauch heraus würde ich sagen es ist die Funktion.

        function make_active_return_active (&$input) {
            if(is_array($input['children'])){
                foreach($input['children'] as $child){
                    $test=make_active_return_active($child);
                    if($test==1){
                        echo $input['name']." ".$test."\n";
                        $input['active'] = 1;
                    }
                }
                return $input['active'];
            }
            elseif($input['active']){
                return $input['active'];
            }
            elseif($input[0]['name']){
                foreach($input as $child){
                    make_active_return_active($child);
                }
            }
        }

        Du hast vergessen vor dem foreach das active auf 0 zu stellen. Das stand da eigentlich, damit vorhandene aktive Werte ggf. zurück gesetzt werden, wenn alle nachfolgenden auch 0 wären. Mag natürlich sein dass du das nicht willst oder nicht brauchst (weil das array ohnehin immer neu mit 0en initiiert wird).  
        Ich fürchte du wirst daher den ganzen Array zurück geben müssen...  
        ~~~php
          
         function make_active_return_active (&$input) {  
             if(is_array($input['children'])){  
                 foreach($input['children'] as $child){  
                     $test=make_active_return_active($child);  
                     if($test['active']==1){ //Zeile veraendert  
                         echo $input['name']." ".$test['active']."\n";  
                         $input['active'] = 1;  
                         $child = $test; //Zeile hinzugefuegt  
                     }  
                 }  
                 return $input; //Zeile geaendert  
             }  
             elseif($input['active']){  
                 return $input; //Zeile geandert  
             }  
        //Wozu ist dieser Teil:  
             elseif($input[0]['name']){  
                 foreach($input as $child){  
                     make_active_return_active($child);  
                 }  
             }  
        //Wozu war dieser Teil oben?  
         }  
        
        

        Vorausgesetzt php übernimmt die Information, die man in $child schreibt ins array. Dann sollte das so oder so ähnlich gehen.
        Den letzten elseif-Block verstehe ich nicht, zumal du die Rückgabe nicht weiter verarbeitest.
        Darüber hinaus gibt es keinen Rückgabewert der Funktion, wenn das übergebene Array keine Kinder hat und inaktiv ist. Daher war mein Pseudocode oben auch so aufgebaut, dass erstmal geändert wird und dann in jedem Fall am Ende returnt.

        --
        sh:( fo:| ch:? rl:( br:& n4:& ie:{ mo:} va:) de:µ_de:] zu:) fl:( ss:| ls:[ js:(