Преобразование массива PHP в дерево JSON

У меня есть массив в этом формате:

array( array('id' => 1, 'parent_id' => null, 'name' => 'lorem ipsum'), array('id' => 2, 'parent_id' => 1, 'name' => 'lorem ipsum1'), array('id' => 3, 'parent_id' => 1, 'name' => 'lorem ipsum2'), array('id' => 4, 'parent_id' => 2, 'name' => 'lorem ipsum3'), array('id' => 5, 'parent_id' => 3, 'name' => 'lorem ipsum4'), array('id' => 6, 'parent_id' => null, 'name' => 'lorem ipsum5'), ); 

Мне нужно преобразовать этот массив в объект json с помощью этого стиля:

 var json = { id: "1", name: "loreim ipsum", data: {}, children: [{ id: "2", name: "lorem ipsum1", data: {}, children: [{ id: "3", name: "lorem ipsum2", data: {}, children: [{ .............. 

Как я могу это сделать? Благодарю.

Мое решение:

 $data = array( array('id' => 1, 'parent_id' => null, 'name' => 'lorem ipsum'), array('id' => 2, 'parent_id' => 1, 'name' => 'lorem ipsum1'), array('id' => 3, 'parent_id' => 1, 'name' => 'lorem ipsum2'), array('id' => 4, 'parent_id' => 2, 'name' => 'lorem ipsum3'), array('id' => 5, 'parent_id' => 3, 'name' => 'lorem ipsum4'), array('id' => 6, 'parent_id' => null, 'name' => 'lorem ipsum5'), ); $itemsByReference = array(); // Build array of item references: foreach($data as $key => &$item) { $itemsByReference[$item['id']] = &$item; // Children array: $itemsByReference[$item['id']]['children'] = array(); // Empty data class (so that json_encode adds "data: {}" ) $itemsByReference[$item['id']]['data'] = new StdClass(); } // Set items as children of the relevant parent item. foreach($data as $key => &$item) if($item['parent_id'] && isset($itemsByReference[$item['parent_id']])) $itemsByReference [$item['parent_id']]['children'][] = &$item; // Remove items that were added to parents elsewhere: foreach($data as $key => &$item) { if($item['parent_id'] && isset($itemsByReference[$item['parent_id']])) unset($data[$key]); } // Encode: $json = json_encode($data); не $data = array( array('id' => 1, 'parent_id' => null, 'name' => 'lorem ipsum'), array('id' => 2, 'parent_id' => 1, 'name' => 'lorem ipsum1'), array('id' => 3, 'parent_id' => 1, 'name' => 'lorem ipsum2'), array('id' => 4, 'parent_id' => 2, 'name' => 'lorem ipsum3'), array('id' => 5, 'parent_id' => 3, 'name' => 'lorem ipsum4'), array('id' => 6, 'parent_id' => null, 'name' => 'lorem ipsum5'), ); $itemsByReference = array(); // Build array of item references: foreach($data as $key => &$item) { $itemsByReference[$item['id']] = &$item; // Children array: $itemsByReference[$item['id']]['children'] = array(); // Empty data class (so that json_encode adds "data: {}" ) $itemsByReference[$item['id']]['data'] = new StdClass(); } // Set items as children of the relevant parent item. foreach($data as $key => &$item) if($item['parent_id'] && isset($itemsByReference[$item['parent_id']])) $itemsByReference [$item['parent_id']]['children'][] = &$item; // Remove items that were added to parents elsewhere: foreach($data as $key => &$item) { if($item['parent_id'] && isset($itemsByReference[$item['parent_id']])) unset($data[$key]); } // Encode: $json = json_encode($data); 

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

Изучите комментарии, чтобы понять, что делает код и почему; и если у вас все еще есть вопросы, спросите их тоже!

 // Assume your array is $data $root = new stdClass; // this is your root item $objectMap = array(); // this holds objects indexed by their id // Since we need to iterate over the array, but there may be no guarantee // that an item's parent will be always encountered before the item itself, // we loop as many times as needed, skipping items whose parent we have not // yet seen. Hopefully we will see it later and be able to process these // items in the next iteration. while (!empty($data)) { // Remember how many items there are when starting the loop $count = count($data); // Do the actual work! foreach ($data as $key => $row) { $parentId = $row['parent_id']; if ($parentId === null) { // We just met the root element $current = $root; } else if (isset($objectMap[$parentId])) { // We met an element with a parent that we have already seen $current = new stdClass; } else { // We met an element with an unknown parent; ignore it for now continue; } // Put the current element on the map so that its children will // be able to find it when we meet them $objectMap[$row['id']] = $current; // Add the item to its parent's children array $objectMap[$parentId]->children[] = $current; // Set the item's properties $current->id = $row['id']; $current->name = $row['name']; $current->data = new stdClass; // always empty $current->children = array(); // We successfully processed this, remove it (see why below!) unset($data[$key]); } // OK, we looped over the array once. If the number of items has // not been reduced at all, it means that the array contains only // items whose parents do not exist. Instead of looping forever, // let's just take what we are given and stop here. if ($count == count($data)) { break; } // If there are still items in $data, we will now iterate again // in the hope of being able to process them in the next iteration } // All set! If $data is not empty now, it means there were items // with invalid parent_ids to begin with. $output = json_encode($root); не // Assume your array is $data $root = new stdClass; // this is your root item $objectMap = array(); // this holds objects indexed by their id // Since we need to iterate over the array, but there may be no guarantee // that an item's parent will be always encountered before the item itself, // we loop as many times as needed, skipping items whose parent we have not // yet seen. Hopefully we will see it later and be able to process these // items in the next iteration. while (!empty($data)) { // Remember how many items there are when starting the loop $count = count($data); // Do the actual work! foreach ($data as $key => $row) { $parentId = $row['parent_id']; if ($parentId === null) { // We just met the root element $current = $root; } else if (isset($objectMap[$parentId])) { // We met an element with a parent that we have already seen $current = new stdClass; } else { // We met an element with an unknown parent; ignore it for now continue; } // Put the current element on the map so that its children will // be able to find it when we meet them $objectMap[$row['id']] = $current; // Add the item to its parent's children array $objectMap[$parentId]->children[] = $current; // Set the item's properties $current->id = $row['id']; $current->name = $row['name']; $current->data = new stdClass; // always empty $current->children = array(); // We successfully processed this, remove it (see why below!) unset($data[$key]); } // OK, we looped over the array once. If the number of items has // not been reduced at all, it means that the array contains only // items whose parents do not exist. Instead of looping forever, // let's just take what we are given and stop here. if ($count == count($data)) { break; } // If there are still items in $data, we will now iterate again // in the hope of being able to process them in the next iteration } // All set! If $data is not empty now, it means there were items // with invalid parent_ids to begin with. $output = json_encode($root); 

Мой прием (я знаю, что ответ принят, но я работал над этим, поэтому я отправлю id = P)

 // Test data $data = array( array('id' => 1, 'parent_id' => null, 'name' => 'lorem ipsum'), array('id' => 2, 'parent_id' => 1, 'name' => 'lorem ipsum1'), array('id' => 3, 'parent_id' => 1, 'name' => 'lorem ipsum2'), array('id' => 4, 'parent_id' => 2, 'name' => 'lorem ipsum3'), array('id' => 5, 'parent_id' => 3, 'name' => 'lorem ipsum4'), array('id' => 6, 'parent_id' => null, 'name' => 'lorem ipsum5'), ); // Randomize, because the data may not be in a top-down order shuffle( $data ); // Parse and inspect the result $builder = new TreeBuilder( $data ); echo '<pre>', print_r( $builder->getTree() ), '</pre>'; class TreeBuilder { protected $leafIndex = array(); protected $tree = array(); protected $stack; function __construct( $data ) { $this->stack = $data; while( count( $this->stack ) ) { $this->branchify( array_shift( $this->stack ) ); } } protected function branchify( &$leaf ) { // Root-level leaf? if ( null === $leaf['parent_id'] ) { $this->addLeaf( $this->tree, $leaf ); } // Have we found this leaf's parent yet? else if ( isset( $this->leafIndex[$leaf['parent_id']] ) ) { $this->addLeaf( $this->leafIndex[$leaf['parent_id']]['children'], $leaf ); } else { // Nope, put it back on the stack $this->stack[] = $leaf; } } protected function addLeaf( &$branch, $leaf ) { // Add the leaf to the branch $branch[] = array( 'id' => $leaf['id'] , 'name' => $leaf['name'] , 'data' => new stdClass , 'children' => array() ); // Store a reference so we can do an O(1) lookup later $this->leafIndex[$leaf['id']] = &$branch[count($branch)-1]; } protected function addChild( $branch, $leaf ) { $this->leafIndex[$leaf['id']] &= $branch['children'][] = $leaf; } public function getTree() { return $this->tree; } }