Если понадобилось связанный список преобразовывать в многомерный иерархический массив это уже говорит о том, что что-то в архитектуре не так.
Но надо так надо, например у WordPress функция get_terms возвращает именно связанный список — одномерный массив, мне как раз потребовалось выбрать определённые группы, вместе с предками.
Можно это было сделать и через запрос, но не дело это лишними запросами нагружать базу.
Из нескольких функций получилась почти универсальная для формирования иерархического массива:
/**
* Пробежимся по всем элементам и составим цепочку родителей - линейный массив айдишников
* @param unknown_type $item
* @param unknown_type $items
* @param unknown_type $levels
* @return array
*/
function parentis($item, $items, &$levels, $keyID, $keyParent) {
$item=(array)$item;
$levels[]=$item[$keyID];
if ($item[$keyParent]!=0) {
return parentis($items[$item[$keyParent]], $items, $levels, $keyID, $keyParent);
}
$levels[]=0;
return $levels;
}
/**
* Уберём более короткие цепочки, которые являются частью более длинных
* @param unknown_type $items
*/
function sanityzeParentis(&$items) {
foreach ($items as $ki => $i) {
foreach ($items as $kj => $j) {
if ($ki==$kj) continue;
$li=count($i);
$lj=count($j);
$l=min($li, $lj);
$match=false;
for ($m=0; $m<$l; $m++) {
if ($i[$m]!=$j[$m]) {
$match=true;
break;
}
}
if (!$match) {
if ($l==$li) unset($items[$ki]); else unset($items[$kj]);
}
}
}
}
/**
* Создадим вложенные массивы по иерархии на основе цепочек
* @param unknown_type $arr
* @param unknown_type $hierarchycal
* @param unknown_type $level
*/
function setChilds(&$arr, $hierarchycal, $items, $level, $keySubChilds, $keyChild) {
if (count($hierarchycal) < $level) return;
$h=$hierarchycal[$level-1];
if (!isset($arr[$h])) $arr[$h]=array($keyChild=>$items[$h], $keySubChilds=>array() );
setChilds($arr[$h][$keySubChilds], $hierarchycal, $items, $level+1, $keySubChilds, $keyChild);
}
/**
* Формируем связанный список (одномерный массив) в многомерный массив с иерархиией
* @param unknown_type $items связанный список
* @param unknown_type $keyID ключ айдишника элемента связанного списка
* @param unknown_type $keyParent ключ айдишника предка элемента связанного списка
* @param unknown_type $keySubChilds ключ, в который будут заноситсья вложенные элементы
* @param unknown_type $keyChild ключ для самого вложенного элемента
* @param unknown_type $levels с какого уровня начинать, обычно с 1
* @return array
*/
function formatHierarchy($items, $keyID, $keyParent, $keySubChilds, $keyChild, $levels ) {
//-- занесём элементы в массив по ключам - айдишникам
$level1= array();
foreach ($items as $item) {
$item=(array)$item;
$level1[$item[$keyID]]=$item;
}
$hierarchycals=array();
foreach ($level1 as $item) {
$hierarchy=array();
$hierarchy=array_reverse(parentis($item, $level1, $hierarchy, $keyID, $keyParent));
$hierarchycals[]=$hierarchy;
}
sanityzeParentis($hierarchycals);
$result=array();
foreach ($hierarchycals as $hierarchy) {
setChilds($result, $hierarchy, $level1, $levels, $keySubChilds, $keyChild );
}
return $result;
}
Основная функция - formatHierarchy Например, имеем связанный список $list у каждого элемента есть поле id, title, parent Элемент с parent==0 считается корневым! Пример:[spoiler]
array (size=10) 0 => array (size=3) 'id' => int 1 'parent' => int 0 'title' => string 'Элемент 1' (length=16) 1 => array (size=3) 'id' => int 2 'parent' => int 0 'title' => string 'Элемент 2' (length=16) 2 => array (size=3) 'id' => int 3 'parent' => int 0 'title' => string 'Элемент 3' (length=16) 3 => array (size=3) 'id' => int 4 'parent' => int 2 'title' => string 'Вложенный Элемент 4' (length=35) 4 => array (size=3) 'id' => int 5 'parent' => int 2 'title' => string 'Вложенный Элемент 5' (length=35) 5 => array (size=3) 'id' => int 6 'parent' => int 3 'title' => string 'Вложенный Элемент 6' (length=35) 6 => array (size=3) 'id' => int 7 'parent' => int 6 'title' => string 'Дважды вложенный Элемент 7' (length=48) 7 => array (size=3) 'id' => int 8 'parent' => int 3 'title' => string 'Дважды вложенный Элемент 8' (length=48) 8 => array (size=3) 'id' => int 9 'parent' => int 3 'title' => string 'Дважды вложенный Элемент 9' (length=48) 9 => array (size=3) 'id' => int 10 'parent' => int 9 'title' => string 'Трижды вложенный Элемент 10' (length=49)[/spoiler]
вызываем тогда так: formatHierarchy($list, ‘id’, ‘parent’, ‘item’, ‘subitems’, 1);
тогда результирующий иерархический массив получится такой:
array (size=1) 0 => array (size=2) 'item' => null 'subitems' => array (size=3) 1 => array (size=2) 'item' => array (size=3) 'id' => int 1 'parent' => int 0 'title' => string 'Элемент 1' (length=16) 'subitems' => array (size=0) empty 2 => array (size=2) 'item' => array (size=3) 'id' => int 2 'parent' => int 0 'title' => string 'Элемент 2' (length=16) 'subitems' => array (size=2) 4 => array (size=2) 'item' => array (size=3) 'id' => int 4 'parent' => int 2 'title' => string 'Вложенный Элемент 4' (length=35) 'subitems' => array (size=0) empty 5 => array (size=2) 'item' => array (size=3) 'id' => int 5 'parent' => int 2 'title' => string 'Вложенный Элемент 5' (length=35) 'subitems' => array (size=0) empty 3 => array (size=2) 'item' => array (size=3) 'id' => int 3 'parent' => int 0 'title' => string 'Элемент 3' (length=16) 'subitems' => array (size=3) 6 => array (size=2) 'item' => array (size=3) 'id' => int 6 'parent' => int 3 'title' => string 'Вложенный Элемент 6' (length=35) 'subitems' => array (size=1) 7 => array (size=2) 'item' => array (size=3) 'id' => int 7 'parent' => int 6 'title' => string 'Дважды вложенный Элемент 7' (length=48) 'subitems' => array (size=0) empty 8 => array (size=2) 'item' => array (size=3) 'id' => int 8 'parent' => int 3 'title' => string 'Дважды вложенный Элемент 8' (length=48) 'subitems' => array (size=0) empty 9 => array (size=2) 'item' => array (size=3) 'id' => int 9 'parent' => int 3 'title' => string 'Дважды вложенный Элемент 9' (length=48) 'subitems' => array (size=1) 10 => array (size=2) 'item' => array (size=3) 'id' => int 10 'parent' => int 9 'title' => string 'Трижды вложенный Элемент 10' (length=49) 'subitems' => array (size=0) empty[/spoiler]