Создание рекурсивной функции дерева деревьев

У меня есть база данных с кучей категорий, некоторые из них:

Array ( [0] => Array ( [id] => 1 [name] => Home Improvement [slug] => Home-Improvement [parent] => [user_id] => 1 [order] => 1 ) [1] => Array ( [id] => 2 [name] => Asbestos Abatement & Removal [slug] => Asbestos-Abatement-Removal [parent] => 1 [user_id] => 1 [order] => 8 ) [2] => Array ( [id] => 3 [name] => Asphalt & Asphalt Products [slug] => Asphalt-Asphalt-Products [parent] => 1 [user_id] => 1 [order] => 9 ) [3] => Array ( [id] => 4 [name] => Bathroom [slug] => Bathroom [parent] => 1 [user_id] => 1 [order] => 10 ) [4] => Array ( [id] => 5 [name] => Kitchen Cabinets [slug] => Kitchen-Cabinets [parent] => 1 [user_id] => 1 [order] => 11 ) [5] => Array ( [id] => 6 [name] => Ceilings [slug] => Ceilings [parent] => 1 [user_id] => 1 [order] => 12 ) [6] => Array ( [id] => 7 [name] => Cleaning [slug] => Cleaning [parent] => 1 [user_id] => 1 [order] => 13 ) [7] => Array ( [id] => 8 [name] => Closet Organizers & Accessories [slug] => Closet-Organizers-Accessories [parent] => 1 [user_id] => 1 [order] => 14 ) [8] => Array ( [id] => 9 [name] => Concrete [slug] => Concrete [parent] => 1 [user_id] => 1 [order] => 15 ) [9] => Array ( [id] => 10 [name] => Contractors & Service Providers [slug] => Contractors-Service-Providers [parent] => 1 [user_id] => 1 [order] => 16 ) 

То, что я пытаюсь вывести, выглядит примерно так:

 <ul> <li>Parent <ul> <li>Child</li> </ul> </li> <li>Parent with no Children</li> </ul> 

Я пытаюсь построить рекурсивный скрипт дерева в PHP, но я застрял. Вот что я до сих пор. Я застрял в том, что делать между остальными: и endif; в преддверии. (И я использую этот синтаксис только для более легкого чтения здесь.) Любые предложения?

 echo $this->categories->makeTree(0, $this->db->get('categories')->result_array()); public static function makeTree($parent, $array) { if (!is_array($array)) return ''; $output = '<ul>'; foreach($array as $key => $value): if ($value['parent'] == $parent): $output .= '<li>'; if ($value['parent'] == NULL): $output .= $value['name']; else: endif; endif; $output .= '</li>'; endforeach; $output .= '</ul>'; return $output; } 

ИЗМЕНИТЬ 1

Я смог получить эту работу, хотя у меня есть вызов базы данных в цикле foreach, что, вероятно, не самая лучшая идея:

 public function makeTree($parent, $array) { if (!is_array($array)) return FALSE; $output = '<ul>'; foreach($array as $key => $value): if ($value['parent'] == $parent): $output .= '<li>'; if ($value['parent'] == NULL): $output .= $value['name']; $subcategories = ci()->db->get_where('categories', array('parent' => $value['id'])); if ($subcategories->num_rows() > 0): $output .= $this->makeTree($value['id'], $subcategories->result_array()); endif; else: $output .= $value['name']; $output .= '</li>'; endif; endif; endforeach; $output .= '</ul>'; return $output; } 

EDIT 2

Вот мое окончательное решение, повторно использующее массив вместо выполнения запроса БД:

 public function makeTree($parent, $array) { if (!is_array($array) OR empty($array)) return FALSE; $output = '<ul>'; foreach($array as $key => $value): if ($value['parent'] == $parent): $output .= '<li>'; if ($value['parent'] == NULL): $output .= $value['name']; $matches = array(); foreach($array as $subkey => $subvalue): if ($subvalue['parent'] == $value['id']): $matches[$subkey] = $subvalue; endif; endforeach; $output .= $this->makeTree($value['id'], $matches); else: $output .= $value['name']; $output .= '</li>'; endif; endif; endforeach; $output .= '</ul>'; return $output; } 

Solutions Collecting From Web of "Создание рекурсивной функции дерева деревьев"

Хотя это кажется отвеченным, посмотрите здесь . С помощью показанной функции вы можете преобразовать ваши плоские данные в вложенные данные только с одной итерацией. Создание ul-списка из этих вложенных данных тогда очень просто. Например:

 function nested2ul($data) { $result = array(); if (sizeof($data) > 0) { $result[] = '<ul>'; foreach ($data as $entry) { $result[] = sprintf( '<li>%s %s</li>', $entry['name'], nested2ul($entry['children']) ); } $result[] = '</ul>'; } return implode($result); } echo nested2ul(array(flat2nested( $yourFlatData )); 

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

Вот мое окончательное решение, повторно использующее массив вместо выполнения запроса БД. Если у вас есть лучшее решение, отправьте сообщение!

 public function makeTree($parent, $array) { if (!is_array($array) OR empty($array)) return FALSE; $output = '<ul>'; foreach($array as $key => $value): if ($value['parent'] == $parent): $output .= '<li>'; if ($value['parent'] == NULL): $output .= $value['name']; $matches = array(); foreach($array as $subkey => $subvalue): if ($subvalue['parent'] == $value['id']): $matches[$subkey] = $subvalue; endif; endforeach; $output .= $this->makeTree($value['id'], $matches); else: $output .= $value['name']; $output .= '</li>'; endif; endif; endforeach; $output .= '</ul>'; return $output; } 

Я обычно использую что-то вроде этого, обратите внимание

1-й этот фрагмент кода использует устаревший mysql_ *

Во-вторых, у вас должно быть одно поле базы данных с именем level, если NULL является основной категорией, если оно имеет число, это подкатегория категории с таким числом как id

 function getFamilies($level = 0) { $level++; $sql = "SELECT id from families WHERE level IS NULL"; if (mysql_num_rows($result) > 0) { echo "<ul>"; while($row = mysql_fetch_assoc($result)) { echo "<li>".$row['id']; getSubFamilies($level, $row['id']); echo "</li>"; } echo "</ul>"; } } function getSubFamilies($level, $id) { $level++; $sqlSubFamilies = "SELECT id FROM families WHERE level = ".$id.""; $resultSubFamilies = mysql_query($sqlSubFamilies); if (mysql_num_rows($resultSubFamilies) > 0) { echo = "<ul>"; while($rowSubFamilies = mysql_fetch_assoc($resultSubFamilies)) { echo "<li>".$rowSubFamilies['id']; getSubFamilies($level, $rowSubFamilies['id']); echo "</li>"; } echo "</ul>"; } } getFamilies($level = 0); 

попробуй это:

 $cats = $this->db->get('categories')->result_array(); echo $this->categories->makeTree(0, $cats); public static function makeTree($parent, $array) { if (!is_array($array)) return ''; $output = '<ul>'; foreach($array as $key => $value): if ($value['parent'] == $parent): $output .= '<li>'; if ($value['parent'] == NULL): $output .= $value['name']; else: endif; endif; $output .= '</li>'; $output .= $this->categories->makeTree($value['parent'], $cats); endforeach; $output .= '</ul>'; return $output; } 

Я думаю, что этот метод с использованием анонимной функции очень прост.

 //--------------------------- PRINT NESTED CATEGORIES $cats_childs = array(); $q = $db->query("SELECT id, parent, name FROM categories"); while ($r = $db->row($q)) { $cats_childs[$r['parent']][$r['id']] = $r; } $nested2ul = function($data) use (&$nested2ul, &$cats_childs) { if (!empty($data)) { echo '<ul>'; foreach ($data as $r) { echo '<li>'; echo $r['name']; $flat2ul($cats_childs[$r['id']]); echo '</li>'; } echo '</ul>'; } }; echo $nested2ul($cats_childs[0]);