Из плоского массива:
$tmp = array(
array('id' => 0, 'level' => 0, 'name' => 'root', 'left' => 1, 'right' => 13),
array('id' => 1, 'level' => 1, 'name' => 'Техотдел', 'left' => 2, 'right' => 8),
array('id' => 2, 'level' => 1, 'name' => 'Отдел кадров', 'left' => 9, 'right' => 10),
array('id' => 3, 'level' => 1, 'name' => 'Экономический отдел', 'left' => 11, 'right' => 12),
array('id' => 4, 'level' => 2, 'name' => 'Подотдел техотдела 1', 'left' => 3, 'right' => 6),
array('id' => 5, 'level' => 2, 'name' => 'Подотдел техотдела 2', 'left' => 7, 'right' => 8),
array('id' => 6, 'level' => 3, 'name' => 'Подподотдел техотдела 1', 'left' => 4, 'right' => 5),
);
Необходимо построить дерево вида:
$tree = array(
array(
'id' => 0,
'level' => 0,
'name' => 'root',
'children' => array(
array(
'id' => 1,
'level' => 1,
'name' => 'Техотдел',
'children' => array(
array(
'id' => 4,
'level' => 2,
'name' => 'Подотдел техотдела 1',
'children' => array(
array(
'id' => 6,
'level' => 3,
'name' => 'Подподотдел техотдела 1'
),
),
),
array(
'id' => 5,
'level' => 2,
'name' => 'Подотдел техотдела 2'
),
),
),
array(
'id' => 2,
'level' => 1,
'name' => 'Отдел кадров'
),
array(
'id' => 3,
'level' => 1,
'name' => 'Экономический отдел'
),
)
),
);
Голову ломаю, не могу сообразить как это сделать.
Наверное, алгоритм решения не один существует, так что простой вариант построения:
Сначала определим максимальную глубину и разложим массив на уровни:
$lmax = max(array_column($tmp, 'level'));
$levels = array_fill(0, $lmax, []);
foreach($tmp as $node){
$levels[$node['level']][] = $node + ['children' => []];
}
Теперь собственно определим функцию построения. На вход нужен родительских узел. Будем перебирать элементы, которые лежат на уровень ниже. Если нижний элемент подходит под граничные условия, то добавляем его к children. Далее запускаем рекурсию.
$build = function(&$root) use (&$build, $levels){
$l = $root['level'] + 1;
if(!isset($levels[$l])) return;
foreach($levels[$l] as &$n){
if(($n['id'] >= $root['left']) && ($n['id'] <= $root['right'])){
$root['children'][] = &$n;
$build($n);
}
}
};
Следует обратить внимание на использование ссылок & как в цикле перебора, так и при добавлении в children
Осталось запустить это дело.
$root = $levels[0][0];
$build($root);
print_r($root);
На выходе искомая структура.
В принципе можно попутно удалять элементы из $levels, которые вносим в children, чтобы в следующие разы (в рекурсиях) их уже не перебирать.
Сборка персонального компьютера от Artline: умный выбор для современных пользователей