Я пытаюсь настроить список, который может иметь несколько уровней, используя parentId
для определения его родителя. Параметр parentId
первого элемента имеет значение NULL. Пример некоторых записей:
id parentId имя 1 NULL item1 2 NULL item2 3 1 пункт3 4 2 item4 5 3 пункт5 6 3 пункт6
Итак, 1 и 2 являются основными пунктами; 3 – ребенок 1; 4 – ребенок 2; 5 – это ребенок из 3 (который является ребенком одного из них); 6 также является ребенком из 3 (который является ребенком одного из них); и т.п.
Я застрял в создании массива, который правильно добавляет эти элементы в нужные уровни. Он должен выглядеть так:
Array ( [1] => Array ( [name] => item1 [parentId] => [children] => Array ( [3] => Array ( [name] => item3 [parentId] => 1 [children] => Array ( [5] => Array ( [name] => item5 [parentId] => 3 ) [6] => Array ( [name] => item6 [parentId] => 3 ) ) ) ) ) [2] => Array ( [name] => item2 [parentId] => [children] => Array ( [4] => Array ( [name] => item4 [parentId] => 2 ) ) ) )
Но скажите, что я просматриваю все элементы, используя foreach()
, и я получаю элемент 5. Его parentId равен 3, но в этот момент я понятия не имею, где этот родитель 3 находится в массиве и как добавить детей в этот родитель.
Есть ли уловка, чтобы перебрать эти предметы и поставить их на место правильно?
Вот оно
// your original data as an array $data = array( array( 'id' => 1, 'parentId' => null, 'name' => 'item1' ), array( 'id' => 2, 'parentId' => null, 'name' => 'item2' ), array( 'id' => 3, 'parentId' => 1, 'name' => 'item3' ), array( 'id' => 4, 'parentId' => 2, 'name' => 'item4' ), array( 'id' => 5, 'parentId' => 3, 'name' => 'item5' ), array( 'id' => 6, 'parentId' => 3, 'name' => 'item6' ), );
Рекурсивная функция
function buildTree( $ar, $pid = null ) { $op = array(); foreach( $ar as $item ) { if( $item['parentId'] == $pid ) { $op[$item['id']] = array( 'name' => $item['name'], 'parentId' => $item['parentId'] ); // using recursion $children = buildTree( $ar, $item['id'] ); if( $children ) { $op[$item['id']]['children'] = $children; } } } return $op; } print_r( buildTree( $data ) ); /* Array ( [1] => Array ( [name] => item1 [parentId] => [children] => Array ( [3] => Array ( [name] => item3 [parentId] => 1 [children] => Array ( [5] => Array ( [name] => item5 [parentId] => 3 ) [6] => Array ( [name] => item6 [parentId] => 3 ) ) ) ) ) [2] => Array ( [name] => item2 [parentId] => [children] => Array ( [4] => Array ( [name] => item4 [parentId] => 2 ) ) ) ) */
Вы должны использовать идентификатор элемента как ключевое значение для массива, чтобы вы могли добавить элемент к его родительскому объекту следующим образом:
$array[$parentID]['children'][$childID] = array();
Первое, что приходит на ум, – это просто плоская версия того, что у вас есть:
array ( [0] => array( 'name' => 'item1', 'parent' => null ), [1] => array( 'name' => 'item2', 'parent' => null ), [3] => array( 'name' => 'item3', 'parent' => 0 ), [4] => array( 'name' => 'item4', 'parent' => 3 ), [5] => array( 'name' => 'item5', 'parent' => 1 ), [6] => array( 'name' => 'item6', 'parent' => 1 ), );
В принципе, вы только ссылаетесь на родителя. Чтобы найти всех детей, вам придется перебирать массив. Однако начальное время настройки было бы довольно быстрым.
Второй, который приходит на ум, и будет включать гораздо больше настроек, но гораздо меньше времени доступа:
array ( [0] => array( 'name' => 'item1', 'parent' => null, 'children' = array(3) ), [1] => array( 'name' => 'item2', 'parent' => null 'children' = array(5, 6) ), [3] => array( 'name' => 'item3', 'parent' => 0 'children' = array(4) ), [4] => array( 'name' => 'item4', 'parent' => 3 'children' = array() ), [5] => array( 'name' => 'item5', 'parent' => 1 'children' = array() ), [6] => array( 'name' => 'item6', 'parent' => 1 'children' = array() ), );
В этом случае вы добавляете все дочерние индексы в родительский. Это займет немного больше времени, но последующее время доступа будет быстрым. Когда вы выясняете родителей, вы просто добавляете массив дочерних элементов.
Единственным реальным недостатком второго подхода является то, что если вы хотите добавить или удалить элемент, вам нужно помнить о возврате и обновлении массива children для родителя.
Вам может не понадобиться новое решение, но это может пригодиться другим пользователям:
// ! assuming $elements is built like: Array( id1 => Array(/*parameters*/) , ...) function buildTree($elements) { $e = Array(0 => Array()); // elements array $r = Array(0 =>& Array()); // reference array while ($elements) {// repeat till $elements is empty // loop through (remaining) elements foreach ($elements as $id => $element) { $pid = $element['parentId']; // shortcut if (array_key_exists($pid,$r)) { // parent already parsed -> can add this element // use parent's reference to elements array to add this element ( $r[$pid] =& $e[path][to][$pid] ) $r[$pid] ['elements'][$id] = $element; // create reference for this element using parent's reference $r[$id] =& $r[$pid]['elements'][$id]; // unset current element in input array in order to limit while-loop unset($elements[$id]); } } } return $e; // or whatever you need, the reference array can be useful if you need to fetch an element only knowing its id }
не// ! assuming $elements is built like: Array( id1 => Array(/*parameters*/) , ...) function buildTree($elements) { $e = Array(0 => Array()); // elements array $r = Array(0 =>& Array()); // reference array while ($elements) {// repeat till $elements is empty // loop through (remaining) elements foreach ($elements as $id => $element) { $pid = $element['parentId']; // shortcut if (array_key_exists($pid,$r)) { // parent already parsed -> can add this element // use parent's reference to elements array to add this element ( $r[$pid] =& $e[path][to][$pid] ) $r[$pid] ['elements'][$id] = $element; // create reference for this element using parent's reference $r[$id] =& $r[$pid]['elements'][$id]; // unset current element in input array in order to limit while-loop unset($elements[$id]); } } } return $e; // or whatever you need, the reference array can be useful if you need to fetch an element only knowing its id }
Что оно делает:
$e
) и добавить корневой элемент ( 0/null
) $r
) и уже ссылаться на $r[0]
на $e[0]
&
after =
!) return
что вам нужно! Преимущества этого метода:
foreach
(вы назначаете больше всего из того, что вы знаете на данный момент) $elements
) Другими словами: он должен быть быстрее (я его не тестировал!), По крайней мере для более сложных задач, таких как тот, для которого я его использую.