1

I've written a function to convert a single dimension array (adjacency list) into a multi dimensional array. I'm trying to inject an enumerated path into $aCat.

Source (single dimension)

[2] => Array
    (
        [id] => 2
        [parent_id] => 0
        [name] => Cat 1 
    )
[45] => Array 
    (
       [id] => 45
       [parent_id] => 2
       [name] => Cat 2
   )
[46] => Array 
    (
       [id] => 46
       [parent_id] => 2
       [name] => Cat 4
   )
[47] => Array 
    (
       [id] => 47
       [parent_id] => 2
       [name] => Cat 5
   )
[10] => Array
   (
       [id] => 10 
       [parent_id] => 45
       [name] => Cat 3
  )

I have the following function to expand this out to multi-dimensional.

function fnExpandArray($aData){
    $aNested = array();

    foreach($aData as &$aCat){

        if(isset($aData[$aCat['parent_id']])){

            $aData[$aCat['parent_id']]['sub'][$aCat['id']] = &$aCat;    

        } else {

            $aNested[$aCat['id']] = &$aCat;

        }

    }

    unset($aCat);

    return $aNested;
}

This is the result. Perfect so far.

[2] => Array
    (
        [id] => 2
        [parent_id] => 0
        [name] => Cat 1
        [sub] => Array
            (
                [45] => Array
                    (
                        [id] => 45
                        [parent_id] => 2
                        [name] => Cat 2 
                        [sub] => Array
                            (
                                [10] => Array
                                    (
                                        [id] => 10
                                        [parent_id] => 45
                                        [name] => Cat 3
                                        [sub] => Array ()
                                    )
                            )
                    )
                [46] => Array
                    (
                        [id] => 46
                        [parent_id] => 2
                        [name] => Cat 4 
                        [sub] => Array()
                     )
                [47] => Array
                    (
                        [id] => 47
                        [parent_id] => 2
                        [name] => Cat 5 
                        [sub] => Array()

How do I end up with:

[2] => Array
    (
        [id] => 2
        [parent_id] => 0
        [name] => Cat 1
        [path] => 2
        [sub] => Array
            (
                [45] => Array
                    (
                        [id] => 45
                        [parent_id] => 2
                        [name] => Cat 2 
                        [path] => 2_45
                        [sub] => Array
                            (
                                [10] => Array
                                    (
                                        [id] => 10
                                        [parent_id] => 45
                                        [name] => Cat 3
                                        [path] => 2_45_10
                                        [sub] => Array ()
                                    )
                            )
                    )
                [46] => Array
                    (
                        [id] => 46
                        [parent_id] => 2
                        [name] => Cat 4 
                        [path] => 2_46
                        [sub] => Array()
                     )
                [47] => Array
                    (
                        [id] => 47
                        [parent_id] => 2
                        [name] => Cat 5
                        [path] => 2_47
                        [sub] => Array()
supert3d
  • 55
  • 7

2 Answers2

0

Modify your function code like this:

function fnExpandArray($aData){
    $aNested = array();

    foreach($aData as &$aCat){

        if(isset($aData[$aCat['parent_id']])){

            $aData[$aCat['parent_id']]['sub'][$aCat['id']] = &$aCat;

            $aData[$aCat['parent_id']]['sub'][$aCat['id']]['path'] = $aData[$aCat['parent_id']]['path'] . '_' . $aCat['id'];

        } else {

            $aNested[$aCat['id']] = &$aCat;

            $aNested[$aCat['id']]['path'] = $aCat['id'];

        }

    }

    unset($aCat);

    return $aNested;
}
Eduardo Galván
  • 962
  • 7
  • 15
  • Cheers Eduardo. I tried similar, but I end up with odd behavior at about 4 levels deep. The "parent_id" isn't getting pre-appended to some of the paths. – supert3d May 16 '16 at 19:40
  • @supert3d I tested it up to 6 levels deep without problems. – Eduardo Galván May 16 '16 at 19:44
  • Could there be another reason? Duplicate id's? Modifying resulting array to more accurately reflect environment. – supert3d May 16 '16 at 19:46
  • @supert3d I tested it with the new source you posted and yes, it gives me the same result as yours. Isn't that what you expect to get? – Eduardo Galván May 16 '16 at 19:55
  • Must be some garbage data in the original array somewhere. Tested with a stripped down version and it works as designed. – supert3d May 16 '16 at 20:04
  • OK; think I've found the root of the issue. In every instance where there is a problem. The "path" index is being injected AFTER the "sub" index. Everywhere else, correctly, it's before. Just need to figure out why that is. – supert3d May 16 '16 at 21:17
0

Solution that worked for me:

This method rewrite resolved my issue. Made multiple passes on the array.

public function fnExpandTaxonomy(&$aData) {

    $aTree = array();

    // Loop original flat array, build associative and inject additional indices as required. 
    foreach($aData as $iKey => &$aCat){
        $aTree[$aCat['id']] = &$aCat;
        $aTree[$aCat['id']]['level'] = 0; 
        $aTree[$aCat['id']]['path'] = $aCat['id']; 
        $aTree[$aCat['id']]['sub'] = array(); 
    }

    // Loop - Add children to parents. 
    foreach($aTree as $iKey => &$aCat) {
        if(!$aCat['parent_id']) continue;

        unset($aCat['level'],$aCat['path'],$aCat['sub']);
        $aCat['level'] = $aTree[$aCat['parent_id']]['level']+1; 
        $aCat['path'] = $aTree[$aCat['parent_id']]['path'].'_'.$aCat['id']; 
        $aTree[$aCat['parent_id']]['sub'][$aCat['id']] = &$aCat;

    }

    // Loop again, remove any items that don't have a parent of 0;
    foreach($aTree as $iKey => &$aCat) {
      if(!$aCat['parent_id']) continue;
      unset($aTree[$iKey]);
    }

    unset($aCat);
    return $aTree;  

}   

Big thank you to pyson, whose answer (below) in another similar thread helped me out.

create array tree from array list

Community
  • 1
  • 1
supert3d
  • 55
  • 7