PHP

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

Еще одна из часто встречающихся задач при разработке сайтов - создание многоуровневых древовидных списков. Отдельные элементы списков хранятся в массиве и объединяются между собой через связку полей "ID элемента" - "Родительский элемент". Это могут быть выпадающие меню с несколькими уровнями субменю, каталоги товаров по категориям, карты сайта и т.п. Попробуем описать трехуровневое вложенное меню. Для этого зададим массив вручную, а в реальной ситуации он может быть, например, получен из базы. Количество уровней вложенности может быть произвольным, три уровня выбраны исключительно для примера.
// Построение из массива древовидного списка без использования рекурсии
$menu=array(
     1=>array('name'=>'Овощи', 'parent'=>0),
         6=>array('name'=>'Капуста', 'parent'=>1),
         7=>array('name'=>'Помидоры', 'parent'=>1),
         9=>array('name'=>'Салат', 'parent'=>1),
             18=>array('name'=>'Китайский салат', 'parent'=>9),
         12=>array('name'=>'Тыква', 'parent'=>1),
         16=>array('name'=>'Редиска', 'parent'=>1),
     2=>array('name'=>'Фрукты', 'parent'=>0),
         13=>array('name'=>'Бананы', 'parent'=>2),
         14=>array('name'=>'Ягоды', 'parent'=>2),
             19=>array('name'=>'Арбуз', 'parent'=>14),
             20=>array('name'=>'Клубника', 'parent'=>14),
     3=>array('name'=>'Животные', 'parent'=>0),
     4=>array('name'=>'Растения', 'parent'=>0),
         8=>array('name'=>'Конопля', 'parent'=>4),
         11=>array('name'=>'Мак', 'parent'=>4),
         17=>array('name'=>'Сахарный тростник', 'parent'=>4),
     5=>array('name'=>'Насекомые', 'parent'=>0),
         10=>array('name'=>'Тараканы', 'parent'=>5),
);

В parent прописан ID родительского элемента для каждого субменю, главное меню (первый уровень) имеет parent=0. Теперь нам надо из этого линейного массива сделать древовидный согласно связям родительских и дочерних элементов. Обычно для этого используется решения с применением рекурсии или же требуется, чтобы исходный массив был специальным образом отсортирован. Но вполне можно обойтись таким вот элегантным решением с использованием ссылок:
// Построение дерева за один проход
foreach($menu as $menu_id=>$data) {
    // Прописать в родительском узле ссылку на пункт меню
    $menu[$data['parent']]['child'][$menu_id]=&$menu[$menu_id];
}
 
// Готовый массив находится в $menu[0]['child']
$sorted_menu=(array)$menu[0]['child'];

Единственное условие, чтобы исходный массив не содержал кольцевых замыканий, это когда родительский элемент ссылается в качестве своего родителя на свой дочерний элемент. Других ограничений нет, массив может быть как угодно отсортирован и иметь "дыры" в нумерации ID.

Массив преобразован в древовидную структуру, теперь его можно вывести на экран или вставить в шаблон сайта.
echo '<ul>';
foreach($sorted_menu as $top_menu) {
    // Меню верхнего уровня
    echo '<li>'.$top_menu['name'];
    if (count($top_menu['child'])) {
        // Субменю второго уровня
        echo '<ul>';
        foreach($top_menu['child'] as $sub_menu) {
            echo '<li>'.$sub_menu['name'];
            if (count($sub_menu['child'])) {
                // Субменю третьего уровня
                echo '<ul>';
                foreach($sub_menu['child'] as $subsub_menu) {
                    echo '<li>'.$subsub_menu['name'].'</li>';
                }
                echo '</ul>';
            }
            echo '</li>';
        }
        echo '</ul>';
    }
    echo '</li>';
}
echo '</ul>';

Если уровень вложенности задан жестко, как в нашем случае, то можно обойтись линейным кодом с несколькими вложенными циклами. А вот для отрисовки вложенных меню или списков произвольной вложенности уже придется использовать рекурсивные функции. Как обычно, вариант решения зависит от конкретной задачи.
Теги:
список, массив
Добавлено: 22 Сентября 2013 02:05:28 Добавил: Андрей Ковальчук Нравится 0
Добавить
Комментарии:
Нету комментариев для вывода...