Blog. Just Blog

Создание древовидного списка из массива

Версия для печати Добавить в Избранное Отправить на E-Mail | Категория: Web-мастеру и не только | Автор: ManHunter
Еще одна из часто встречающихся задач при разработке сайтов - создание многоуровневых древовидных списков. Отдельные элементы списков хранятся в массиве и объединяются между собой через связку полей "ID элемента" - "Родительский элемент". Это могут быть выпадающие меню с несколькими уровнями субменю, каталоги товаров по категориям, карты сайта и т.п. Попробуем описать трехуровневое вложенное меню. Для этого зададим массив вручную, а в реальной ситуации он может быть, например, получен из базы. Количество уровней вложенности может быть произвольным, три уровня выбраны исключительно для примера.
  1. // Построение из массива древовидного списка без использования рекурсии
  2. $menu=array(
  3.      1=>array('name'=>'Овощи''parent'=>0),
  4.          6=>array('name'=>'Капуста''parent'=>1),
  5.          7=>array('name'=>'Помидоры''parent'=>1),
  6.          9=>array('name'=>'Салат''parent'=>1),
  7.              18=>array('name'=>'Китайский салат''parent'=>9),
  8.          12=>array('name'=>'Тыква''parent'=>1),
  9.          16=>array('name'=>'Редиска''parent'=>1),
  10.      2=>array('name'=>'Фрукты''parent'=>0),
  11.          13=>array('name'=>'Бананы''parent'=>2),
  12.          14=>array('name'=>'Ягоды''parent'=>2),
  13.              19=>array('name'=>'Арбуз''parent'=>14),
  14.              20=>array('name'=>'Клубника''parent'=>14),
  15.      3=>array('name'=>'Животные''parent'=>0),
  16.      4=>array('name'=>'Растения''parent'=>0),
  17.          8=>array('name'=>'Конопля''parent'=>4),
  18.          11=>array('name'=>'Мак''parent'=>4),
  19.          17=>array('name'=>'Сахарный тростник''parent'=>4),
  20.      5=>array('name'=>'Насекомые''parent'=>0),
  21.          10=>array('name'=>'Тараканы''parent'=>5),
  22. );
В parent прописан ID родительского элемента для каждого субменю, главное меню (первый уровень) имеет parent=0. Теперь нам надо из этого линейного массива сделать древовидный согласно связям родительских и дочерних элементов. Обычно для этого используется решения с применением рекурсии или же требуется, чтобы исходный массив был специальным образом отсортирован. Но вполне можно обойтись таким вот элегантным решением с использованием ссылок:
  1. // Построение дерева за один проход
  2. foreach($menu as $menu_id=>$data) {
  3.     // Прописать в родительском узле ссылку на пункт меню
  4.     $menu[$data['parent']]['child'][$menu_id]=&$menu[$menu_id];
  5. }
  6.  
  7. // Готовый массив находится в $menu[0]['child']
  8. $sorted_menu=(array)$menu[0]['child'];
Единственное условие, чтобы исходный массив не содержал кольцевых замыканий, это когда родительский элемент ссылается в качестве своего родителя на свой дочерний элемент. Других ограничений нет, массив может быть как угодно отсортирован и иметь "дыры" в нумерации ID.

Массив преобразован в древовидную структуру, теперь его можно вывести на экран или вставить в шаблон сайта.
  1. echo '<ul>';
  2. foreach($sorted_menu as $top_menu) {
  3.     // Меню верхнего уровня
  4.     echo '<li>'.$top_menu['name'];
  5.     if (count($top_menu['child'])) {
  6.         // Субменю второго уровня
  7.         echo '<ul>';
  8.         foreach($top_menu['child'] as $sub_menu) {
  9.             echo '<li>'.$sub_menu['name'];
  10.             if (count($sub_menu['child'])) {
  11.                 // Субменю третьего уровня
  12.                 echo '<ul>';
  13.                 foreach($sub_menu['child'] as $subsub_menu) {
  14.                     echo '<li>'.$subsub_menu['name'].'</li>';
  15.                 }
  16.                 echo '</ul>';
  17.             }
  18.             echo '</li>';
  19.         }
  20.         echo '</ul>';
  21.     }
  22.     echo '</li>';
  23. }
  24. echo '</ul>';
Если уровень вложенности задан жестко, как в нашем случае, то можно обойтись линейным кодом с несколькими вложенными циклами. А вот для отрисовки вложенных меню или списков произвольной вложенности уже придется использовать рекурсивные функции. Как обычно, вариант решения зависит от конкретной задачи.

Поделиться ссылкой ВКонтакте Поделиться ссылкой на Facebook Поделиться ссылкой на LiveJournal Поделиться ссылкой в Мой Круг Добавить в Мой мир Добавить на ЛиРу (Liveinternet) Добавить в закладки Memori Добавить в закладки Google
Просмотров: 11102 | Комментариев: 11

Метки: PHP
Внимание! Статья опубликована больше года назад, информация могла устареть!

Комментарии

Отзывы посетителей сайта о статье
THomZone (29.09.2015 в 09:25):
Спасибо огромное
fif (17.04.2015 в 10:39):
Помогите приспособить это решение для вывода списка категорий с дочками с постраничной навигацией.
ManHunter (07.04.2015 в 11:37):
Ахуеть! В детском садике выходной что ли? Скрипткиддисов отпустили домой мамкину сиську пососать? Иди нахуй, уебок.
sas (07.04.2015 в 10:14):
<img src='javascript:alert()'>
Иван (03.07.2013 в 11:46):
Спасибо за простоту решения.
[p0-[ (15.03.2013 в 23:54):
[-[[
Droid (26.08.2011 в 02:10):
Можете показать версию где массив данных берётся из БД ?
Александр (09.08.2011 в 14:05):
Мне лично больше нравиться рекурсия ) Просто и компактно. Да и редактировать проще ее. Скажем, если будет необходимо прописать не просто тег <li>, а <li class="my_li">, то надо будет три раза исправлять вместо одного ) Либо пользоваться Ctrl+F )
eGo (07.08.2011 в 07:40):
А я уже тут размечтался, думал появился тот самый гуру что придумал функцию для нерекурсивного вывода массива со структурой adjacency list
Megabyte (21.05.2011 в 00:13):
Огромное человеческое спасибо!
prohozhiy (03.05.2011 в 11:24):
4=>array('name'=>'Растения', 'parent'=>0),
         8=>array('name'=>'Конопля', 'parent'=>4),
         11=>array('name'=>'Мак', 'parent'=>4)
Растения похоже не совсем случайно выбирались :-)

Добавить комментарий

Заполните форму для добавления комментария
Имя*:
Текст комментария (не более 2000 символов)*:

*Все поля обязательны для заполнения.
Комментарии, содержащие рекламу, ненормативную лексику, оскорбления и т.п., а также флуд и сообщения не по теме, будут удаляться. Нарушителям может быть заблокирован доступ к сайту.
Наверх
Powered by PCL's Speckled Band Engine 0.2 RC3
© ManHunter / PCL, 2008-2023
При использовании материалов ссылка на сайт обязательна
Время генерации: 0.06 сек. / MySQL: 3 (0.0041 сек.) / Память: 4.5 Mb
Наверх