Recursive array parse with nested nodes

Viewed 193

I have blackhole in my mind. Im trying to parse array with multilevel nodes. Here's example array:

global $array;
$array = [
    '0' => [
        'id' => 1,
        'parent' => 0,
        'name' => 'root 0'
    ],
    '1' => [
        'id' => 2,
        'parent' => 1,
        'name' => 'root 1'
    ],
    '2' => [
        'id' => 3,
        'parent' => 2,
        'name' => 'root 2'
    ],
    '3' => [
        'id' => 4,
        'parent' => 3,
        'name' => 'root 3'
    ],
    '4' => [
        'id' => 5,
        'parent' => 3,
        'name' => 'root 4'
    ],
    '5' => [
        'id' => 6,
        'parent' => 2,
        'name' => 'root 2'
    ]
];

This should looks after parse like this. Element 3 with parent 3 should have parent 1, because element 2 has parent 2, and its first child.

I trying to get to this using foreach and function:

global $new_array;
$new_array = [];

foreach( $array as $item )
{
    if( $item['parent'] == 0 ) {
        $new_array[] = $item; // if parent 0 - clone into new array
        continue;
    }

    //echo $item['name'] . PHP_EOL;
    $new_array[] = check_parent( $item['parent'] ); 

}

print_r($new_array);

function check_parent( $parent )
{
    //echo '- check for parent of ' . $parent . PHP_EOL;
    global $array;
    foreach( $array as $item ) {
        if( $item['id'] == $parent && $item['parent'] == 0 ) {
            //echo '[OK] found root parent id: ' . $item['id'] . PHP_EOL;
            $item['parent'] = $item['id'];
            return $item;
        } else {
            return check_parent( $item['id'] );
        }
    }
}

I'm so confused, but I didn't see where I make a mistake. Maybe someone, can help me to see - where's problem. I working on it few hours and for now, I had blackhole in my mind.

Fiddle: https://implode.io/jHS8m1

Desired output:

$new_array = [
    '0' => [
        'id' => 1,
        'parent' => 0,
        'name' => 'root 0'
    ],
    '1' => [
        'id' => 2,
        'parent' => 1,
        'name' => 'root 1'
    ],
    '2' => [
        'id' => 3,
        'parent' => 2, // this should have after parse parent 1
        'name' => 'root 2'
    ],
    '3' => [
        'id' => 4,
        'parent' => 3, // this should have after parse parent 1
        'name' => 'root 3'
    ],
    '4' => [
        'id' => 5,
        'parent' => 3, // this should have after parse parent 1
        'name' => 'root 4'
    ],
    '5' => [
        'id' => 6,
        'parent' => 2, // this should have after parse parent 1
        'name' => 'root 2'
    ]
];

Thanks !

2 Answers

Replace the following line in your code

        $new_array[] = check_parent( $item['parent'] ); // get child

with below lines of code.

        $temp = check_parent( $item['parent'] ); // get child
        $item['parent'] = $temp['id'];
        $new_array[] = $item;

What is happening is that your check_parent is returning the $item, which happens to be the parent. However, we are only interested in the id of this. So we get the id and replace the parent it in the original $item.

Here is the working Demo

A bit tardy in my response, but I think it is valuable to provide a refined recursive solution.

My snippet:

  1. Modifies by reference
  2. Does not leverage a global variable declaration
  3. Uses just one loop in the custom recursive function.

Code: (Demo)

function replaceParent(&$array, $parent = null) {
    foreach ($array as &$item) {
        if ($item['id'] == $parent) {
            if ($item['parent']) {
                return replaceParent($array, $item['parent']);
            } else {
                return $item['id'];
            }
        } elseif ($item['parent']) {
            $item['parent'] = replaceParent($array, $item['parent']);
        }
    }
}

replaceParent($array);
var_export($array);

I'll try to explain...

  • id 1's parent value of 0 fails both primary conditions, so no recursion/processing is performed on that row of data.

  • id 2's parent value of 1 passes the elseif condition, so the recursive call goes in search of the row with an id of 1. Finding id 1 with a parent value of 0 means the else branch is satisfied and the id value of 1 is passed back through the recursive call to be assigned to $item['parent'] for the original id 2.

  • To process id 3 (or deeper), multiple recursive calls occur and all conditions play a role in the search and assignment process. First the elseif leads to the first recursion, then the if's if leads to the second recursion, finally the if's else passes the root id's value all the way back to the original grandchild.

Related