PHP Создание многомерного массива из массива с реляционными данными

Возможный дубликат:
Преобразование массива из одного в многомерный на основе значений родительского идентификатора

Я работаю в PHP.

У меня есть следующий массив, который имеет реляционные данные (дочерние отношения родителей).

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 ) [6036] => Array ( [id] => 6036 [name] => Sara Johnson [parent] => 5273 ) [6037] => Array ( [id] => 6037 [name] => Dave Wilson [parent] => 5273 ) [6038] => Array ( [id] => 6038 [name] => Amy Martin [parent] => 6037 ) ) 

Мне нужно, чтобы он был в этом формате JSON:

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

Я знаю, что мне нужно создать многомерный массив и запустить его через json_encode (). Я также считаю, что этот метод, используемый для этого, должен быть рекурсивным, поскольку данные реального мира могут иметь неизвестное количество уровней.

Я был бы рад продемонстрировать некоторые из моих подходов, но они не сработали.

Может кто-нибудь мне помочь?

Меня попросили поделиться моей работой. Это то, что я пробовал, но я не понял, что близко, я не знаю, насколько это полезно.

Я создал массив отношений.

 foreach($array as $k => $v){ $relationships[$v['id']] = $v['parent']; } 

Я думаю (на основе другого сообщения SO) использовались эти реляционные данные для создания нового многомерного массива. Если бы я получил это на работу, я собирался работать над добавлением правильных «детских» ярлыков и т. Д.

 $childrenTable = array(); $data = array(); foreach ($relationships as $n => $p) { //parent was not seen before, put on root if (!array_key_exists($p, $childrenTable)) { $childrenTable[$p] = array(); $data[$p] = &$childrenTable[$p]; } //child was not seen before if (!array_key_exists($n, $childrenTable)) { $childrenTable[$n] = array(); } //root node has a parent after all, relocate if (array_key_exists($n, $data)) { unset($data[$n]); } $childrenTable[$p][$n] = &$childrenTable[$n]; } unset($childrenTable); print_r($data); не $childrenTable = array(); $data = array(); foreach ($relationships as $n => $p) { //parent was not seen before, put on root if (!array_key_exists($p, $childrenTable)) { $childrenTable[$p] = array(); $data[$p] = &$childrenTable[$p]; } //child was not seen before if (!array_key_exists($n, $childrenTable)) { $childrenTable[$n] = array(); } //root node has a parent after all, relocate if (array_key_exists($n, $data)) { unset($data[$n]); } $childrenTable[$p][$n] = &$childrenTable[$n]; } unset($childrenTable); print_r($data); с $childrenTable = array(); $data = array(); foreach ($relationships as $n => $p) { //parent was not seen before, put on root if (!array_key_exists($p, $childrenTable)) { $childrenTable[$p] = array(); $data[$p] = &$childrenTable[$p]; } //child was not seen before if (!array_key_exists($n, $childrenTable)) { $childrenTable[$n] = array(); } //root node has a parent after all, relocate if (array_key_exists($n, $data)) { unset($data[$n]); } $childrenTable[$p][$n] = &$childrenTable[$n]; } unset($childrenTable); print_r($data); 

     <?php header('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

    Хорошо, вот как это работает, вы на самом деле не слишком далеко, как вы начали, но то, что вы на самом деле ищете, – это ссылки. Это общая процедура:

    Поскольку существует связь между родительским и дочерним узлами на их идентификаторе, вам сначала нужно проиндексировать данные на основе идентификатора. Я делаю это здесь с массивом ( $rows ), чтобы имитировать ваш доступ к данным, если вы читаете из базы данных, это будет похоже. С помощью этой индексации вы также можете добавить дополнительные свойства, такие как ваши пустые данные:

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

    Итак, теперь все записи индексируются по их идентификатору. Это был первый шаг.

    Второй шаг одинаково прямолинейный. Поскольку теперь мы можем получить доступ к каждому узлу на основе его идентификатора в $index , мы можем назначить его родителям.

    Существует один «виртуальный» узел, то есть тот, у которого есть идентификатор 0. Он не существует ни в одной из строк, однако, если бы мы могли добавить к нему детей, мы можем использовать эту дочернюю коллекцию в качестве хранилища для всех корневых узлов, в вашем случае есть один корневой узел.

    Конечно, для ID 0 мы не должны обрабатывать родителя – потому что он не существует.

    Итак, давайте сделаем это. Мы используем ссылки здесь, потому что иначе один и тот же узел не может быть как родительским, так и дочерним:

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

    Поскольку мы используем ссылки, последняя строка заботится о том, чтобы удалить ссылку, хранящуюся в $row после цикла.

    Теперь все дети были назначены родителям. Возможно, это уже так, но не забывайте о последнем шаге, к которому нужно получить фактический узел для выхода.

    Для краткости просто назначьте корневой узел самому $index . Если мы помним, единственный корневой узел, который мы хотим, является первым в массиве children в узле с идентификатором 0 :

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

    Вот и все. Мы можем использовать его прямо сейчас, чтобы создать JSON:

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

    Наконец, весь код с первого взгляда:

     <?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 tree foreach($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 json header('Content-Type: application/json'); echo json_encode($index, JSON_PRETTY_PRINT); с <?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 tree foreach($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 json header('Content-Type: application/json'); echo json_encode($index, JSON_PRETTY_PRINT); 

    Который создал бы следующий json (здесь с 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": { } } ] } ] } 

    Следующий код выполнит эту работу. Возможно, вы захотите немного подстроить в соответствии с вашими потребностями.

     $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); с $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); с $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