0

I'm trying to rebuild a tree as a flat array. I successed in the function of attributing the parent_id to each element.

But now my issue is to store each element in a new array, which is outside of the function.

I've tried several ways (ps: the function is not defined in the same page as where it's called):

   function rebuildTreeAsFlatArray($source,$childrenPropertyName)          
   {     
       $myarray = array();
       foreach($source as $element)
       {

           if(isset($element["nodes"]))
           {
               $this->rebuildTreeAsFlatArray($element["nodes"],$childrenPropertyName);
           }
           array_push($myarray,$element);


       }
       return $myarray;
   }
$result = $arrayFunctionsTreeSaving->rebuildTreeAsFlatArray($tree,"nodes");

this gives me an array with only one element inside, the first one.

I've tried to use a global:

function rebuildTreeAsFlatArray($source,$childrenPropertyName)          
   {     
       global $myarray;
       foreach($source as $element)
       {

           if(isset($element["nodes"]))
           {
               $this->rebuildTreeAsFlatArray($element["nodes"],$childrenPropertyName);
           }
           array_push($myarray,$element);                     
       }

   }
   $myarray = array();
   $arrayFunctionsTreeSaving->rebuildTreeAsFlatArray($tree,"nodes");

and what's the reuslt: Warning: array_push() expects parameter 1 to be array, null given

Last but not least, but referenced parameter:

   function rebuildTreeAsFlatArray($source,$childrenPropertyName,array &$result)          
   {     

       foreach($source as $element)
       {

           if(isset($element[$childrenPropertyName]))
           {
               $this->rebuildTreeAsFlatArray($element[$childrenPropertyName],$childrenPropertyName,$result);
           }
           array_push($result,$element);                     
       }

   }
   $myarray = array();
   $arrayFunctionsTreeSaving->rebuildTreeAsFlatArray($tree,"nodes",$myarray);

and this gives me:

Catchable Fatal Error: Argument 3 passed to NRtworks\GlobalUtilsFunctionsBundle\Services\arrayFunctionsTreeSaving::rebuildTreeAsFlatArray() must be of the type array, integer given

now what should I do ? I'm lost

Here is a tree example:

array(10) {
    ["id"] = > int(6)["name"] = > string(9)"Subsidies" ["code"] = > string(6)"703000" ["sense"] = > string(2)"DR" ["lft"] = > int(11)["lvl"] = > int(2)["rgt"] = > int(20)["root"] = > int(1)["nodes"] = > array(2) {
        [0] = > array(10) {
            ["id"] = > int(29)["name"] = > string(13)"Subsidies USA" ["code"] = > string(6)"703200" ["sense"] = > string(2)"DR" ["lft"] = > int(12)["lvl"] = > int(3)["rgt"] = > int(13)["root"] = > int(1)["nodes"] = > array(0) {}
            ["$$hashKey"] = > string(3)"01Z"
        }
        [1] = > array(10) {
            ["id"] = > int(12)["name"] = > string(14)"Subventions FR" ["code"] = > string(6)"703100" ["sense"] = > string(2)"DR" ["lft"] = > int(14)["lvl"] = > int(3)["rgt"] = > int(19)["root"] = > int(1)["nodes"] = > array(0) {}
            ["$$hashKey"] = > string(3)"020"
        }
    }
    ["$$hashKey"] = > string(3)"00R"
}
Eagle1
  • 810
  • 2
  • 12
  • 30

3 Answers3

0

I have change your first function to merge seceond method call with previous results. I dont have the rest of your class so function is untested.

function rebuildTreeAsFlatArray($source,$childrenPropertyName)          
 {     
   $myarray = array();
   foreach($source as $element)
   {

       if(isset($element["nodes"]))
       {
          $ret = $this->rebuildTreeAsFlatArray($element["nodes"],$childrenPropertyName); //modified
           array_merge($myarray, $ret); // added
       }
       array_push($myarray,$element);


   }
   return $myarray;
}
Matej Žvan
  • 758
  • 4
  • 13
  • humm, when I still have only one element in it... and when I change merge to push it becomes a mess. I added a tree example so you can test it if you want... – Eagle1 Dec 04 '14 at 18:24
0

Explanation to the error message

and what's the reuslt: Warning: array_push() expects parameter 1 to be array, null given

The statement

global $myarray;

means: Let us import a global variable named $myarray. The variable should exist. In your case, it doesn't exist before - it is created and initialized as null.

To initialize $myarray correctly as an empty array, you could add a line before your function:

$myarray = array();

But as you know, global variables aren't good design.

fjf2002
  • 872
  • 5
  • 15
  • so in fact, whenever a function is defined in another file (like 98% of the time) you can't use global ? – Eagle1 Dec 04 '14 at 19:25
  • I do not fully understand your comment, but... if you say "global x;" and then use that variable, you assume there was a global variable defined before that function definition, and there was assigned to it a proper value. – fjf2002 Dec 04 '14 at 19:28
  • Nevertheless, using globals is bad coding. – fjf2002 Dec 04 '14 at 19:28
0

The usual approach to a depth-First search is like this:

function depthFirstPostfixSearch($theTree) {

    function theRecursion($subTree, &$accumulatingArray) {
        foreach($subTree["nodes"] as $node) {
            theRecursion($node, $accumulatingArray);
        }
        $accumulatingArray[] = $subTree;
    }

    $accumulatingArray = array();
    theRecursion($theTree, $accumulatingArray);
    return $accumulatingArray;
}

Do not forget the ampersand in the declaration of theRecursion - this means passing the array parameter as reference. Otherwise, a copy of the array will be made on each function call.

The function-inside-function allows to globally expose a convenient interface while internally, an additional parameter is passed between recursions.

In your special problem here, you don't seem to deal with a tree, but rather with an array of trees - you will have to modify my example slightly.

fjf2002
  • 872
  • 5
  • 15
  • ok this looks better than my example. You are missing some semicolumns(;). This is just a thot but shuld you/he unset node from element before puting it to $accumul...? – Matej Žvan Dec 04 '14 at 19:44
  • @Matej Zvan: >You are missing some semicolumns(;)< YES. I had to mess with VB6 the last few days :-( ... that made me forget semicolons – fjf2002 Dec 04 '14 at 20:07
  • @Matej: >shuld you/he unset node from element before puting it to $accumul...?< Hmm. Depends on the particular purpose. Let me put it this way: Nothing goes wrong in building and using the accumulatingArray if we keep the parent<->child relationship that attibute "nodes" represents – fjf2002 Dec 04 '14 at 20:14
  • I'm disappointed that I didn't think of this structure. just for the sake of correctness, could you move $accumulatingArray[] = $node; into the foreach ? – Eagle1 Dec 05 '14 at 14:26
  • Ah, there was an error here, thanks. Either write "$accumulatingArray[] = $subTree;" after the loop, or "$accumulatingArray[] = $node;" in the loop. Semantics change a bit: Version #2 won't contain the root node. – fjf2002 Dec 07 '14 at 21:39