'PHP logic to build multi level tree

Updated

I have the following array, for example:

[{id:1},{id:2}{id:3},{id:4},{id:5},...{id:20}]

May I ask how to generate a JSON object as below in order to achieve the following tree in Image 1? It does not need a parent id as it is first come first serve and each node will only have direct 3 childs.

I think it will run through a function and append the children to the object. Also I wish to control the number of childrens in the future too. Thanks in advance

JSON object

{
    "tree": {
        "id": 1,
        "children": [
            {
                "id": 2,
                "children": [
                    {
                        "id": 5,
                        "children": [
                            {
                                "id": 11
                            },
                            {
                                "id": 12
                            },
                            {
                                "id": 13
                            }
                        ]
                    },
                    {
                        "id": 6
                    },
                    {
                        "id": 7
                    }
                ]
            },
            {
                "id": 3,
                "children": [
                    {
                        "id": 8
                    },
                    {
                        "id": 9
                    },
                    {
                        "id": 10
                    }
                ]
            },
            {
                "id": 4,
                "children": [
                    {
                        "id": 11
                    },
                    {
                        "id": 12
                    },
                    {
                        "id": 13
                    }
                ]
            }
        ]
    }
}

Image 1: the tree illustration

enter image description here



Solution 1:[1]

First of all your JSON object contains duplicate id's.

So the logic is - take first element, mark it as a current_parent. Every subsequent element is placed into a parents_queue and placed into a current_parent children array. If current_parent children array is 3 elements length, take the next node from parents_queue and mark it as a current_parent. Sample code:

// Generate test data
$data = [];
foreach(range(1,20) as $i)
  $data[] = ['id' => $i];

// Tree root and helper vars
$root = null;
$current_parent_node_pointer = null;
$parents_queue = [];

for( $i = 0; $i < count($data); $i++ ){

  $node = &$data[$i];

  // Not the first element
  if( $i ){
    
    if( empty( $current_parent_node_pointer['children'] ) )
      $current_parent_node_pointer['children'] = [];

    // Add the node to current parent
    $current_parent_node_pointer['children'][] = &$node;

    // Current parent has 3 children now, take a new one from the queue;
    if( count( $current_parent_node_pointer['children'] ) == 3 ){
      unset($current_parent_node_pointer); // destroy the reference before assining a new value
      $current_parent_node_pointer = &$parents_queue[0];
      array_shift($parents_queue); // remove current parent from the queue
    }

    // Add current node to the parents queue
    $parents_queue[] = &$node;

  }
  // First element; actually an initialization
  else {
    $root = &$node;
    $current_parent_node_pointer = &$node;
  }
}

$json = json_encode( ['tree' => $root] );

UPD: if your input is an array of objects, code becomes slightly simpler (no reference usage needed):

// Generate test data
$data = [];
foreach(range(1,20) as $i)
  $data[] = (object)['id' => $i];

// Tree root and helper vars
$root = null;
$current_parent_node_pointer = null;
$parents_queue = [];

foreach($data as $node){

  // Not the first element
  if( !empty($current_parent_node_pointer) ){
    
    if( empty( $current_parent_node_pointer->children ) )
      $current_parent_node_pointer->children = [];

    // Add the node to current parent
    $current_parent_node_pointer->children[] = $node;

    // Current parent has 3 children now, take a new one from the queue;
    if( count( $current_parent_node_pointer->children ) == 3 )
      $current_parent_node_pointer = array_shift($parents_queue);

    // Add current node to the parents queue
    $parents_queue[] = $node;

  }
  // First element; actually an initialization
  else {
    $root = $node;
    $current_parent_node_pointer = $node;
  }
}

$json = json_encode( ['tree' => $root] );

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1