Я просмотрел интернет и не совсем нашел то, что искал. У меня есть плоский массив с каждым элементом, содержащим «id» и «parent_id». Каждый элемент будет иметь только один родительский элемент, но может иметь несколько дочерних элементов. Если parent_id = 0, он считается элементом уровня корня. Я пытаюсь получить свой плоский массив в дерево. Другие образцы, которые я нашел, только копируют элемент в родительский, но оригинал все еще существует.
РЕДАКТИРОВАТЬ
Каждый элемент стартового массива считывается из отдельного XML-файла. Сам файл будет иметь значение «0» в качестве значения parent_id, если у него нет родителя. Ключи на самом деле являются строками.
Прошу прощения за замешательство раньше. Надеюсь, это более понятно:
/РЕДАКТИРОВАТЬ
Мой начальный массив:
массив ( [_319_] => Массив ( [id] => 0 [parent_id] => 0 ) [_320_] => Массив ( [id] => _320_ [parent_id] => 0 ) [_321_] => Массив ( [id] => _321_ [parent_id] => _320_ ) [_322_] => Массив ( [id] => _322_ [parent_id] => _321_ ) [_323_] => Массив ( [id] => _323_ [parent_id] => 0 ) [_324_] => Массив ( [id] => _324_ [parent_id] => _323_ ) [_325_] => Массив ( [id] => _325_ [parent_id] => _320_ ) )
Получившийся массив после дерева:
массив ( [_319_] => Массив ( [id] => _319_ [parent_id] => 0 ) [_320_] => Массив ( [id] => _320_ [parent_id] => 0 [children] => Массив ( [_321_] => Массив ( [id] => _321_ [parent_id] => _320_ [children] => Массив ( [_322_] => Массив ( [id] => _322_ [parent_id] => _321_ ) ) ) [_325_] => Массив ( [id] => _325_ [parent_id] => _320_ ) ) [_323_] => Массив ( [id] => _323_ [parent_id] => 0 [children] => Массив ( [_324_] => Массив ( [id] => _324_ [parent_id] => _323_ ) ) )
Любая помощь / руководство очень ценится!
Некоторый код, который у меня есть до сих пор:
function buildTree (array & $ elements, $ parentId = 0) { $ branch = array (); foreach ($ elements as $ element) { if ($ element ['parent_id'] == $ parentId) { $ children = $ this-> buildTree ($ elements, $ element ['id']); if ($ children) { $ element ['children'] = $ children; } $ branch [] = $ element; } } return $ branch; }
Вы забыли unset()
в там брата.
function buildTree(array &$elements, $parentId = 0) { $branch = array(); foreach ($elements as $element) { if ($element['parent_id'] == $parentId) { $children = buildTree($elements, $element['id']); if ($children) { $element['children'] = $children; } $branch[$element['id']] = $element; unset($elements[$element['id']]); } } return $branch; }
неfunction buildTree(array &$elements, $parentId = 0) { $branch = array(); foreach ($elements as $element) { if ($element['parent_id'] == $parentId) { $children = buildTree($elements, $element['id']); if ($children) { $element['children'] = $children; } $branch[$element['id']] = $element; unset($elements[$element['id']]); } } return $branch; }
Решение ImmortalFirefly работает, однако, как указывает mrded, это не спасает первых родителей без детей. Я отредактировал функцию, чтобы исправить эту проблему:
function buildTree(array &$elements, $parentId = 0) { $branch = array(); foreach ($elements as &$element) { if ($element['parent_id'] == $parentId) { $children = buildTree($elements, $element['id']); if ($children) { $element['children'] = $children; } $branch[$element['id']] = $element; unset($element); } } return $branch; }
сfunction buildTree(array &$elements, $parentId = 0) { $branch = array(); foreach ($elements as &$element) { if ($element['parent_id'] == $parentId) { $children = buildTree($elements, $element['id']); if ($children) { $element['children'] = $children; } $branch[$element['id']] = $element; unset($element); } } return $branch; }
Это работает для меня:
$index=array(); $tree=array(); foreach ($ori as $key=>$var) { $var=array_shift($ori); if ($var['id']==0) $var['id']=$key; if ((string)$var['parent_id']==='0') { $tree[$key]=$var; $index[$key]=&$tree[$key]; } else if (isset($index[$var['parent_id']])) { if (!isset($index[$var['parent_id']]['children'])) $index[$var['parent_id']]['children']=array(); $index[$var['parent_id']]['children'][$key]=$var; $index[$key]=&$index[$var['parent_id']]['children'][$key]; } else { array_push($ori,$var); } } unset($index); print_r($tree);
с$index=array(); $tree=array(); foreach ($ori as $key=>$var) { $var=array_shift($ori); if ($var['id']==0) $var['id']=$key; if ((string)$var['parent_id']==='0') { $tree[$key]=$var; $index[$key]=&$tree[$key]; } else if (isset($index[$var['parent_id']])) { if (!isset($index[$var['parent_id']]['children'])) $index[$var['parent_id']]['children']=array(); $index[$var['parent_id']]['children'][$key]=$var; $index[$key]=&$index[$var['parent_id']]['children'][$key]; } else { array_push($ori,$var); } } unset($index); print_r($tree);
Я вижу логику, за исключением этого в результате:
Array ( [0] => Array ( [id] => 0 [parent_id] => 0 ) [1] => Array ( [id] => 1 [parent_id] => 0 )
ИМХО, является parent_id = o, не должен ли [1] быть ребенком [0] здесь?
Во всяком случае, ссылки на спасение:
$tree = array(); foreach($inputarray as $item){ if(!isset($tree[$item['id']])) $tree[$item['id']] = array(); $tree[$item['id']] = array_merge($tree[$item['id']],$item); if(!isset($tree[$item['parent_id']])) $tree[$item['parent_id']] = array(); if(!isset($tree[$item['parent_id']]['children'])) $tree[$item['parent_id']]['children'] = array(); $tree[$item['parent_id']]['children'][] = &$tree[$item['id']]; } $result = $tree[0]['children']; unset($tree); print_r($result);
с$tree = array(); foreach($inputarray as $item){ if(!isset($tree[$item['id']])) $tree[$item['id']] = array(); $tree[$item['id']] = array_merge($tree[$item['id']],$item); if(!isset($tree[$item['parent_id']])) $tree[$item['parent_id']] = array(); if(!isset($tree[$item['parent_id']]['children'])) $tree[$item['parent_id']]['children'] = array(); $tree[$item['parent_id']]['children'][] = &$tree[$item['id']]; } $result = $tree[0]['children']; unset($tree); print_r($result);
Поскольку вы злоупотребляли 0 как «магическим» номером как root, так и существующим id, теперь мы имеем рекурсию в ветке id = 0. Добавление if($item['parent_id']!=$item['id'])
перед $tree[$item['parent_id']]['children'][] = &$tree[$item['id']];
может предотвратить это, но это не очень.
Возможно, исходный массив немного отличается, вы можете использовать эту функцию (parent_id, id, title):
$q = mysql_query("SELECT id, parent_id, name FROM categories"); while ($r = mysql_fetch_row($q)) { $names[$r[0]] = $r[2]; $children[$r[0]][] = $r[1]; } function render_select($root=0, $level=-1) { global $names, $children; if ($root != 0) echo '<option>' . strrep(' ', $level) . $names[$root] . '</option>'; foreach ($children[$root] as $child) render_select($child, $level+1); } echo '<select>'; render_select(); echo '</select>';
Хотя это старый вопрос, я собираюсь опубликовать свой ответ здесь:
/* assuming top level pid = 0 */ $rows = array ( array ( 'id' => 1, 'pid' => 0 ), /* ... */ ); /* make id become array key */ $rows = array_column ( $rows, null, 'id' ); foreach ( $rows as $key => $val ) { if ( $val ['pid'] ) { if ( isset ( $rows [$val ['pid']] )) { $rows [$val ['pid']]['children'][] = &$rows [$key]; } } } foreach ( $rows as $key => $val ) { if ( $val ['pid'] ) unset ( $rows [$key] ); }
array_column
– это PHP 5.5, но вы можете сделать свой собственный легко.
Вы хотите смотреть на хранение и загрузку иерархических данных в MySQL, поскольку я должен решить несколько проблем. Я предполагаю, что первый массив представляет данные, полученные непосредственно из базы данных?
Похоже, вы пытаетесь использовать модель смежности для организации своих данных в структуре иерархии. Есть и другие способы достижения этой цели с помощью гнездования. Если вы не берете эти данные из базы данных, это может быть не так полезно.
Эта ссылка должна помочь вам: http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/
Вот мое решение, идеально работает, если предположить, что верхний уровень parent_id = 0:
function MakeTree($arr){ $parents_arr=array(); foreach ($arr as $key => $value) { $parents_arr[$value['pid']][$value['id']]=$value; } $tree=$parents_arr['0']; $this->createTree($tree, $parents_arr); return $tree; } function createTree(&$tree, $parents_arr){ foreach ($tree as $key => $value) { if(!isset($value['children'])) { $tree[$key]['children']=array(); } if(array_key_exists($key, $parents_arr)){ $tree[$key]['children']=$parents_arr[$key]; $this->createTree($tree[$key]['children'], $parents_arr); } } }
Это мое решение, копирование и оптимизация других решений.
function buildTree(array &$elements, $parentId = 0) { $branch = array(); foreach ($elements as $key => $element) { if ($element['parent_id'] == $parentId) { $children = $this->buildTree($elements, $key); if ($children) { $element['children'] = $children; } $branch[$key] = $element; unset($elements[$key]); } } return $branch; }
неfunction buildTree(array &$elements, $parentId = 0) { $branch = array(); foreach ($elements as $key => $element) { if ($element['parent_id'] == $parentId) { $children = $this->buildTree($elements, $key); if ($children) { $element['children'] = $children; } $branch[$key] = $element; unset($elements[$key]); } } return $branch; }