PHP Create a Multidimensional Array from an array with relational data [duplicate] PHP Create a Multidimensional Array from an array with relational data [duplicate] json json

PHP Create a Multidimensional Array from an array with relational data [duplicate]


<?phpheader('Content-Type: application/json; charset="utf-8"');/** * Helper function *  * @param array   $d   flat data, implementing a id/parent id (adjacency list) structure * @param mixed   $r   root id, node to return * @param string  $pk  parent id index * @param string  $k   id index * @param string  $c   children index * @return array */function makeRecursive($d, $r = 0, $pk = 'parent', $k = 'id', $c = 'children') {  $m = array();  foreach ($d as $e) {    isset($m[$e[$pk]]) ?: $m[$e[$pk]] = array();    isset($m[$e[$k]]) ?: $m[$e[$k]] = array();    $m[$e[$pk]][] = array_merge($e, array($c => &$m[$e[$k]]));  }  return $m[$r][0]; // remove [0] if there could be more than one root nodes}echo json_encode(makeRecursive(array(  array('id' => 5273, 'parent' => 0,    'name' => 'John Doe'),    array('id' => 6032, 'parent' => 5273, 'name' => 'Sally Smith'),  array('id' => 6034, 'parent' => 6032, 'name' => 'Mike Jones'),  array('id' => 6035, 'parent' => 6034, 'name' => 'Jason Williams'),  array('id' => 6036, 'parent' => 5273, 'name' => 'Sara Johnson'),  array('id' => 6037, 'parent' => 5273, 'name' => 'Dave Wilson'),  array('id' => 6038, 'parent' => 6037, 'name' => 'Amy Martin'),)));

demo: https://3v4l.org/s2PNC


Okay, this is how it works, you were actually not too far off as you started, but what you actually look for are references. This is a general procedure:

As there is a relation between parent and child-nodes on their ID, you first need to index the data based on the ID. I do this here with an array ($rows) to simulate your data access, if you read from the database, it would be similar. With this indexing you can also add additional properties like your empty data:

// create an index on id$index = array();foreach($rows as $row){    $row['data'] = (object) array();    $index[$row['id']] = $row;}

So now all entries are indexed on their ID. This was the first step.

The second step is equally straight forward. Because we now can access each node based on it's ID in the $index, we can assign the children to their parent.

There is one "virtual" node, that is the one with the ID 0. It does not exists in any of the rows, however, if we could add children to it too, we can use this children collection as the store for all root nodes, in your case, there is a single root node.

Sure, for the ID 0, we should not process the parent - because it does not exists.

So let's do that. We make use of references here because otherwise the same node could not be both parent and child:

// build the treeforeach($index as $id => &$row){    if ($id === 0) continue;    $parent = $row['parent'];    $index[$parent]['children'][] = &$row;}unset($row);

Because we use references, the last line takes care to unset the reference stored in $row after the loop.

Now all children have been assigned to their parents. That could it be already, however lets not forget the last step, the actual node for the output should be accessed.

For brevity, just assign the root node to the $index itself. If we remember, the only root node we want is the first one in the children array in the node with the ID 0:

// obtain root node$index = $index[0]['children'][0];

And that's it. We can use it now straight away to generate the JSON:

// output jsonheader('Content-Type: application/json');echo json_encode($index);

Finally the whole code at a glance:

<?php/** * @link http://stackoverflow.com/questions/11239652/php-create-a-multidimensional-array-from-an-array-with-relational-data */$rows = array(    array('id' => 5273, 'parent' => 0,    'name' => 'John Doe'),    array('id' => 6032, 'parent' => 5273, 'name' => 'Sally Smith'),    array('id' => 6034, 'parent' => 6032, 'name' => 'Mike Jones'),    array('id' => 6035, 'parent' => 6034, 'name' => 'Jason Williams'),    array('id' => 6036, 'parent' => 5273, 'name' => 'Sara Johnson'),    array('id' => 6037, 'parent' => 5273, 'name' => 'Dave Wilson'),    array('id' => 6038, 'parent' => 6037, 'name' => 'Amy Martin'),);// create an index on id$index = array();foreach($rows as $row){    $row['data'] = (object) [];    $index[$row['id']] = $row;}// build the treeforeach($index as $id => &$row){    if ($id === 0) continue;    $parent = $row['parent'];    $index[$parent]['children'][] = &$row;}unset($row);// obtain root node$index = $index[0]['children'][0];// output jsonheader('Content-Type: application/json');echo json_encode($index, JSON_PRETTY_PRINT);

Which would create the following json (here with PHP 5.4s' JSON_PRETTY_PRINT):

{    "id": 5273,    "parent": 0,    "name": "John Doe",    "data": {    },    "children": [        {            "id": 6032,            "parent": 5273,            "name": "Sally Smith",            "data": {            },            "children": [                {                    "id": 6034,                    "parent": 6032,                    "name": "Mike Jones",                    "data": {                    },                    "children": [                        {                            "id": 6035,                            "parent": 6034,                            "name": "Jason Williams",                            "data": {                            }                        }                    ]                }            ]        },        {            "id": 6036,            "parent": 5273,            "name": "Sara Johnson",            "data": {            }        },        {            "id": 6037,            "parent": 5273,            "name": "Dave Wilson",            "data": {            },            "children": [                {                    "id": 6038,                    "parent": 6037,                    "name": "Amy Martin",                    "data": {                    }                }            ]        }    ]}


Following code will do the job.. you may want to tweak a bit according to your needs.

$data = array(    '5273' => array( 'id' =>5273, 'name'=> 'John Doe', 'parent'=>''),    '6032' => array( 'id' =>6032, 'name'=> 'Sally Smith', 'parent'=>'5273'),    '6034' => array( 'id' =>6034, 'name'=> 'Mike Jones ', 'parent'=>'6032'),    '6035' => array( 'id' =>6035, 'name'=> 'Jason Williams', 'parent'=>'6034')    );$fdata = array();function ConvertToMulti($data) {    global $fdata;    foreach($data as $k => $v)    {        if(empty($v['parent'])){            unset($v['parent']);        $v['data'] = array();        $v['children'] = array();            $fdata[] = $v;        }        else {            findParentAndInsert($v, $fdata);        }    }}function findParentAndInsert($idata, &$ldata) {    foreach ($ldata as $k=>$v) {        if($ldata[$k]['id'] == $idata['parent']) {            unset($idata['parent']);        $idata['data'] = array();        $idata['children'] = array();            $ldata[$k]['children'][] = $idata;            return;        }        else if(!empty($v['children']))            findParentAndInsert($idata, $ldata[$k]['children']);    }}print_r($data);ConvertToMulti($data);echo "AFTER\n";print_r($fdata);

http://codepad.viper-7.com/Q5Buaz