Advertisement
rfv123

stackoverflow/29405568/Recursive function to create tree

Apr 3rd, 2015
422
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 4.55 KB | None | 0 0
  1. <?php // https://stackoverflow.com/questions/29396521/recursive-function-to-create-a-folder-tree-from-array
  2.  
  3. /*
  4.  * source data notes:
  5.  * 1) It not load in one pass.
  6.  *
  7.  * 2) The node 666 will fail to be added as there no parent for it - ever!
  8.  *
  9.  *  - this is important when testing
  10.  *    As when adding nodes in a 'random order' we cannot be sure that all
  11.  *    'source nodes' belong in the 'tree'! The code must allow for that.
  12.  */
  13.  
  14. $source = Array (
  15.    4 =>   Array("name" => "folder4",   "id" => 4,   "folder_id" => 3),
  16.    11 =>  Array("name" => "folder11",  "id" => 11,  "folder_id" => 3),
  17.    13 =>  Array("name" => "folder13",  "id" => 13,  "folder_id" => 12),
  18.    31 =>  Array("name" => "folder31",  "id" => 31,  "folder_id" => 99),
  19.    12 =>  Array("name" => "folder12",  "id" => 12,  "folder_id" => 98),
  20.    42 =>  Array("name" => "folder42",  "id" => 42,  "folder_id" => 32),
  21.    32 =>  Array("name" => "folder32",  "id" => 32,  "folder_id" => 99),
  22.    666 => Array("name" => "folder666", "id" => 666, "folder_id" => 9999),
  23.    99 =>   Array("name" => "folder99Root",   "id" => 99,   "folder_id" => null),
  24.    3 =>   Array("name" => "folder3",   "id" => 3,   "folder_id" => 98),
  25.    33 =>  Array("name" => "folder33",  "id" => 33,  "folder_id" => 99),
  26.    98 =>   Array("name" => "folder98Root",   "id" => 98,   "folder_id" => null),
  27. );
  28.  
  29. // extract the root nodes as we need those first...
  30. $roots = array_filter($source, function($data) {
  31.                                   return is_null($data['folder_id']);
  32.                                });
  33.  
  34. // we need a list of child nodes that haven't been added yet
  35. $sourceKeys = array_diff(array_keys($source), array_keys($roots));
  36.  
  37. // var_dump($sourceKeys, $roots, array_keys($source));
  38.  
  39. // output tree built in here
  40. $theTree = array();
  41.  
  42. // first we need to insert the roots... worth doing as a separate pass...
  43. foreach($roots as  $idx => $folderInfo) {
  44.     insertNode($theTree, $folderInfo['folder_id'], $folderInfo['id'], $folderInfo);
  45. }
  46.  
  47. // now we do multiple passes down the source trying to insert nodes.
  48. // We know we have finished when nothing is inserted during the pass.
  49.  
  50. // for efficiency, we will drive off the sourceKeys array after removing
  51. // any inserted entries...
  52.  
  53. do {
  54.     $insertCount = 0;
  55.  
  56.     foreach($sourceKeys as $position => $idx) {
  57.  
  58.         $folderInfo = $source[$idx];
  59.         $inserted = insertNode($theTree, $folderInfo['folder_id'], $folderInfo['id'], $folderInfo);
  60.         if ($inserted) {
  61.             $insertCount++;
  62.             unset($sourceKeys[$position]); // it is safe to do this in 'foreach'
  63.         }
  64.     }
  65.  
  66. } while ($insertCount > 0);
  67.  
  68. // report nodes not inserted... this may be useful
  69. foreach($sourceKeys as $idx) {
  70.         var_dump('not inserted:', $source[$idx]);
  71. }
  72.  
  73. // output the tree
  74. echo '<pre>', 'Children are in the same order as the input array.', '<br />';
  75.     print_r($theTree);
  76. echo '</pre>';
  77. exit;
  78.  
  79.  
  80. /**
  81.  * Insert:  Find the 'parent' node
  82.  *              if child not found within parent then insert a 'node'
  83.  *
  84.  * @param array node passed by reference as the new node will be inserted
  85.  * @param integer $parentId - root Id - may be null it indicate a 'root'
  86.  * @param integer $childId
  87.  * @param array   $folderInfo - the 'node data' to be stored
  88.  *                 This will always contain an entry called 'children'
  89.  *                 that will be a list of 'child nodes' under this node.
  90.  *
  91.  * @return boolean  true if parentId found and child alive
  92.  *                   false if parent not found anywhere in the tree
  93.  */
  94. function insertNode(&$node, $parentId, $childId, $folderInfo) {
  95.  
  96.     // is Root Node?
  97.     if (is_null($parentId)) {
  98.         $node[$childId] = $folderInfo;
  99.         $node[$childId]['children'] = array();
  100.         return true;
  101.     }
  102.  
  103.     // is this the required parent?
  104.     if (isset($node[$parentId])) { // this node will be processed
  105.         if (!isset($node[$parentId]['children'][$childId])) {
  106.             $node[$parentId]['children'][$childId] = array_merge($folderInfo,
  107.                                            array('children' => array())); // add child node
  108.             return true;
  109.         }
  110.         return true; // end of processing
  111.     }
  112.  
  113.     // check all the children of this node...
  114.     foreach($node as $idx => &$child) { // need the reference
  115.         if (count($child['children']) >= 1) { // check the children...
  116.             if (insertNode($child['children'], $parentId, $childId, $folderInfo)) {
  117.                 return true;
  118.             }
  119.         }
  120.     }
  121.     return false; // parentId not in the tree
  122. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement