Плоский массив PHP для дерева иерархии

У меня есть массив со следующими ключами

id parent_id name 

Пример массива:

 array(7) { [0]=> array(3) { ["id"]=> string(1) "4" ["parent_id"]=> string(1) "0" ["name"]=> string(16) "Top Level Page 4" } [1]=> array(3) { ["id"]=> string(1) "5" ["parent_id"]=> string(1) "1" ["name"]=> string(19) "Second Level Page 1" } [2]=> array(3) { ["id"]=> string(1) "6" ["parent_id"]=> string(1) "2" ["name"]=> string(19) "Second Level Page 2" } [3]=> array(3) { ["id"]=> string(1) "7" ["parent_id"]=> string(1) "5" ["name"]=> string(18) "Third Level Page 1" } [4]=> array(3) { ["id"]=> string(1) "3" ["parent_id"]=> string(1) "0" ["name"]=> string(16) "Top Level Page 3" } [5]=> array(3) { ["id"]=> string(1) "2" ["parent_id"]=> string(1) "0" ["name"]=> string(16) "Top Level Page 2" } [6]=> array(3) { ["id"]=> string(1) "1" ["parent_id"]=> string(1) "0" ["name"]=> string(16) "Top Level Page 1" } } 

То, что я хотел бы сделать, это отобразить дерево иерархии с использованием этого массива, код, который у меня есть в настоящий момент, создает:

 Top Level Page 4 --Second Level Page 1 ---Second Level Page 2 ----Third Level Page 1 Top Level Page 3 Top Level Page 2 Top Level Page 1 

В идеале мне нужно получить результат ниже, но с неограниченным уровнем:

 Top Level Page 4 -Second Level Page 1 -Second Level Page 2 --Third Level Page 1 Top Level Page 3 Top Level Page 2 Top Level Page 1 

Код, который у меня есть до сих пор:

 $level = 1; foreach ($data as $row) { if ($row['parent_id'] == 0) { echo $row['name'] . '<br/>'; } else { $level++; foreach ($data as $m) { if ($m['parent_id'] === $row['parent_id']) { $c = 0; $append = ''; while ($c < $level) { $append.="-"; $c++; } echo $append . $row['name'] . '<br/>'; } } } } } 

Если бы кто-нибудь мог дать мне несколько указаний о том, как добиться этого, это будет очень признательно.

Я нашел решение здесь: Создайте вложенный список из массива PHP для поля выпадающего списка

Вы должны использовать рекурсию.

Здесь пример кода:

 $datas = array( array('id' => 1, 'parent' => 0, 'name' => 'Page 1'), array('id' => 2, 'parent' => 1, 'name' => 'Page 1.1'), array('id' => 3, 'parent' => 2, 'name' => 'Page 1.1.1'), array('id' => 4, 'parent' => 3, 'name' => 'Page 1.1.1.1'), array('id' => 5, 'parent' => 3, 'name' => 'Page 1.1.1.2'), array('id' => 6, 'parent' => 1, 'name' => 'Page 1.2'), array('id' => 7, 'parent' => 6, 'name' => 'Page 1.2.1'), array('id' => 8, 'parent' => 0, 'name' => 'Page 2'), array('id' => 9, 'parent' => 0, 'name' => 'Page 3'), array('id' => 10, 'parent' => 9, 'name' => 'Page 3.1'), array('id' => 11, 'parent' => 9, 'name' => 'Page 3.2'), array('id' => 12, 'parent' => 11, 'name' => 'Page 3.2.1'), ); function generatePageTree($datas, $parent = 0, $depth=0){ $ni=count($datas); if($ni === 0 || $depth > 1000) return ''; // Make sure not to have an endless recursion $tree = '<ul>'; for($i=0; $i < $ni; $i++){ if($datas[$i]['parent'] == $parent){ $tree .= '<li>'; $tree .= $datas[$i]['name']; $tree .= generatePageTree($datas, $datas[$i]['id'], $depth+1); $tree .= '</li>'; } } $tree .= '</ul>'; return $tree; } echo(generatePageTree($datas)); 

Вы можете протестировать его по адресу: http://phpfiddle.org/main/code/1qy-5fj

Или, если вам нужен точный формат:

 function generatePageTree($datas, $parent = 0, $depth = 0){ $ni=count($datas); if($ni === 0 || $depth > 1000) return ''; // Make sure not to have an endless recursion $tree = ''; for($i=0; $i < $ni; $i++){ if($datas[$i]['parent'] == $parent){ $tree .= str_repeat('-', $depth); $tree .= $datas[$i]['name'] . '<br/>'; $tree .= generatePageTree($datas, $datas[$i]['id'], $depth+1); } } return $tree; } 

Тест: http://phpfiddle.org/main/code/jw3-s1j

Вы можете использовать класс FlatToTreeConverter из вспомогательной библиотеки Gears:

 <?php namespace Cosmologist\Gears\Collection; /** * Class able to convert a flat array with parent ID's to a nested tree */ class FlatToTreeConverter { /** * Convert a flat array with parent ID's to a nested tree * * @link http://blog.tekerson.com/2009/03/03/converting-a-flat-array-with-parent-ids-to-a-nested-tree/ * * @param array $array Flat array * @param string $idKeyName Key name for the element containing the item ID * @param string $parentIdKey Key name for the element containing the parent item ID * @param string $childNodesField Key name for the element for placement children * * @return array */ public static function convert(array $array, $idKeyName = 'id', $parentIdKey = 'parentId', $childNodesField = 'children') { $indexed = array(); // first pass - get the array indexed by the primary id foreach ($array as $row) { $indexed[$row[$idKeyName]] = $row; $indexed[$row[$idKeyName]][$childNodesField] = array(); } // second pass $root = array(); foreach ($indexed as $id => $row) { $indexed[$row[$parentIdKey]][$childNodesField][$id] = &$indexed[$id]; if (!$row[$parentIdKey]) { $root[$id] = &$indexed[$id]; } } return $root; } } 

Не уверен, что вы нашли ответ еще, но сегодня я искал одно и то же решение и, наконец, решил создать собственное решение. Код ниже – это класс, который я только что создал, и он работает с массивами и объектами PHP и является рекурсивным для неограниченного количества измерений.

GitHub https://github.com/DukeOfMarshall/PHP-Array-Heirarchy-Display

Простым примером использования этого кода будет:

 <?php require_once('Arrays.class.php'); $display = new Array_Functions(); $display->display_hierarchy($multidimensional_array); ?> 

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

 <?php class Array_Functions { public $number_of_tabs = 3; # The default number of tabs to use when branching out private $counter = 0; # The counter to use for the number of tab iterations to use on the current branch public $display_square_brackets = TRUE; public $display_squiggly_brackets = FALSE; public $display_parenthesis = FALSE; public $display_apostrophe = TRUE; public $display_quotes = FALSE; public function __construct(){ } /** * Displays the array in an organized heirarchy and even does so recursively * * $array ARRAY - The array to display in a heirarchy * * $key_bookends STRING - The character to place on either side of the array key when printed * @@ square - Displays a set of square brackets around the key (DEFAULT) * @@ squiggly - Displays a set of squiggly brackets around the key * @@ parenthesis - Displays a set of parenthesis around the key * @@ FALSE - Turns off the display of bookends around the array key * * $key_padding STRING - The padding to use around the array key with printed * @@ quotes - Pads the array key with double quotes when printed * @@ apostrophe - Pads the array key with apostrophes when printed (DEFAULT) * @@ FALSE - Turns off the display of padding around the array key * * $number_of_tabs_to_use INT - The number of tabs to use when a sub array within the array creates a branch in the heirarchy * */ public function display_hierarchy($array, $key_bookends = '', $key_padding = '', $number_of_tabs_to_use = ''){ # Convert the input to a JSON and then back to an array just to make sure we know what we're working with $array = $this->convert_object_to_array($array); # If the $array variable is still not an array, then error out. # We're not going to fool around with your stupidity if(gettype($array) != 'array'){ echo 'Value submitted was '.strtoupper(gettype($array)).' instead of ARRAY or OBJECT. Only arrays or OBJECTS are allowed Terminating execution.'; exit(); } # Establish the bookend variables if($key_bookends != '' || !$key_bookends){ if(strtolower($key_bookends) == 'square'){ $this->display_square_brackets = TRUE; $this->display_squiggly_brackets = FALSE; $this->display_parenthesis = FALSE; }elseif(strtolower($key_bookends) == 'squiggly'){ $this->display_square_brackets = TRUE; $this->display_squiggly_brackets = TRUE; $this->display_parenthesis = FALSE; }elseif(strtolower($key_bookends) == 'parenthesis'){ $this->display_square_brackets = FALSE; $this->display_squiggly_brackets = FALSE; $this->display_parenthesis = TRUE; }elseif(!$key_bookends){ $this->display_square_brackets = FALSE; $this->display_squiggly_brackets = FALSE; $this->display_parenthesis = FALSE; } } # Establish the padding variables if($key_padding != '' || !$key_padding){ if(strtolower($key_padding) == 'apostrophe'){ $this->display_apostrophe = TRUE; $this->display_quotes = FALSE; }elseif(strtolower($key_padding) == 'quotes'){ $this->display_apostrophe = FALSE; $this->display_quotes = TRUE; }elseif(!$key_padding){ $this->display_apostrophe = FALSE; $this->display_quotes = FALSE; } } # Establish variable for the number of tabs if(isset($number_of_tabs_to_use) && $number_of_tabs_to_use != ''){ $this->number_of_tabs = $number_of_tabs_to_use; } foreach($array as $key => $value){ $this->insert_tabs(); if(is_array($value)){ echo $this->display_padding($key)." => {<BR>"; $this->counter++; $this->display_hierarchy($value); $this->counter--; $this->insert_tabs(); echo '} <BR>'; }else{ echo $this->display_padding($key)." => ".$value.'<BR>'; } } } # Inserts tab spaces for sub arrays when a sub array triggers a branch in the heirarchy # Helps to make the display more human readable and easier to understand private function insert_tabs(){ for($i=1; $i<=$this->counter; $i++){ for($x=1; $x<=$this->number_of_tabs; $x++){ echo '&emsp;'; } } } # Takes a PHP object and converts it to an array # Works with single dimension and multidimensional arrays public function convert_object_to_array($object){ $object = json_decode(json_encode($object), TRUE); return $object; } # Sets the displayed padding around the array keys when printed on the screen public function display_padding($value){ $default_container = "['VALUE_TO_REPLACE']"; $value = str_replace("VALUE_TO_REPLACE", $value, $default_container); if($this->display_square_brackets){ }elseif($this->display_squiggly_brackets){ $value = str_replace('[', '{', $value); $value = str_replace(']', '}', $value); }elseif($this->display_parenthesis){ $value = str_replace('[', '(', $value); $value = str_replace(']', ')', $value); }else{ $value = str_replace('[', '', $value); $value = str_replace(']', '', $value); } if($this->display_apostrophe){ }elseif($this->display_quotes){ $value = str_replace("'", '"', $value); }else{ $value = str_replace("'", '', $value); } return $value; } } ?>