从数组列表创build数组树

我有这样的列表:

array( array(id=>100, parentid=>0, name=>'a'), array(id=>101, parentid=>100, name=>'a'), array(id=>102, parentid=>101, name=>'a'), array(id=>103, parentid=>101, name=>'a'), ) 

但方式更大,所以我需要一个有效的方法,使这个像这样的结构树:

 array( id=>100, parentid=>0, name=>'a', children=>array( id=>101, parentid=>100, name=>'a', children=>array( id=>102, parentid=>101, name=>'a', id=>103, parentid=>101, name=>'a', ) ) ) 

我不能使用像嵌套集或类似的东西,因为我可以在我的数据库中添加左侧和右侧的值。 有任何想法吗?

这是我如何解决它:

 $arr = array( array('id'=>100, 'parentid'=>0, 'name'=>'a'), array('id'=>101, 'parentid'=>100, 'name'=>'a'), array('id'=>102, 'parentid'=>101, 'name'=>'a'), array('id'=>103, 'parentid'=>101, 'name'=>'a'), ); $new = array(); foreach ($arr as $a){ $new[$a['parentid']][] = $a; } $tree = createTree($new, array($arr[0])); print_r($tree); function createTree(&$list, $parent){ $tree = array(); foreach ($parent as $k=>$l){ if(isset($list[$l['id']])){ $l['children'] = createTree($list, $list[$l['id']]); } $tree[] = $l; } return $tree; } 

小修复,如果你需要超过1 parentid [0]元素:)

 $arr = array( array('id'=>100, 'parentid'=>0, 'name'=>'a'), array('id'=>101, 'parentid'=>100, 'name'=>'a'), array('id'=>102, 'parentid'=>101, 'name'=>'a'), array('id'=>103, 'parentid'=>101, 'name'=>'a'), ); $new = array(); foreach ($arr as $a){ $new[$a['parentid']][] = $a; } $tree = createTree($new, $new[0]); // changed print_r($tree); function createTree(&$list, $parent){ $tree = array(); foreach ($parent as $k=>$l){ if(isset($list[$l['id']])){ $l['children'] = createTree($list, $list[$l['id']]); } $tree[] = $l; } return $tree; } 

Thunderstriker变体的一个重做 – 所有的逻辑在一个function:

 function buildTree($flat, $pidKey, $idKey = null) { $grouped = array(); foreach ($flat as $sub){ $grouped[$sub[$pidKey]][] = $sub; } $fnBuilder = function($siblings) use (&$fnBuilder, $grouped, $idKey) { foreach ($siblings as $k => $sibling) { $id = $sibling[$idKey]; if(isset($grouped[$id])) { $sibling['children'] = $fnBuilder($grouped[$id]); } $siblings[$k] = $sibling; } return $siblings; }; $tree = $fnBuilder($grouped[0]); return $tree; } // Example: $flat = [ ['id'=>100, 'parentID'=>0, 'name'=>'a'], ['id'=>101, 'parentID'=>100, 'name'=>'a'], ['id'=>102, 'parentID'=>101, 'name'=>'a'], ['id'=>103, 'parentID'=>101, 'name'=>'a'], ]; $tree = buildTree($flat, 'parentID', 'id'); print_r($tree); 

游乐场: https : //www.tehplayground.com/5V8QSqnmFJ2wcIoj

这是我从阿瑟尔的返工中改编出来的 :

 /* Recursive branch extrusion */ function createBranch(&$parents, $children) { $tree = array(); foreach ($children as $child) { if (isset($parents[$child['id']])) { $child['children'] = $this->createBranch($parents, $parents[$child['id']]); } $tree[] = $child; } return $tree; } /* Initialization */ function createTree($flat, $root = 0) { $parents = array(); foreach ($flat as $a) { $parents[$a['parent']][] = $a; } return $this->createBranch($parents, $parents[$root]); } 

使用:

 $tree = createTree($flat); 

我创build了一个不寻常的('基于while的'而不是recursion的),但多维sorting函数,走arrays,直到没有任何孤儿。 这里的function:

 function treeze( &$a, $parent_key, $children_key ) { $orphans = true; $i; while( $orphans ) { $orphans = false; foreach( $a as $k=>$v ) { // is there $a[$k] sons? $sons = false; foreach( $a as $x=>$y ) if( isset($y[$parent_key]) and $y[$parent_key]!=false and $y[$parent_key]==$k ) { $sons=true; $orphans=true; break; } // $a[$k] is a son, without children, so i can move it if( !$sons and isset($v[$parent_key]) and $v[$parent_key]!=false ) { $a[$v[$parent_key]][$children_key][$k] = $v; unset( $a[$k] ); } } } } 

build议:数组中每个元素的关键必须是元素本身的ID。 例:

 $ARRAY = array( 1 => array( 'label' => "A" ), 2 => array( 'label' => "B" ), 3 => array( 'label' => "C" ), 4 => array( 'label' => "D" ), 5 => array( 'label' => "one", 'father' => '1' ), 6 => array( 'label' => "two", 'father' => '1' ), 7 => array( 'label' => "three", 'father' => '1' ), 8 => array( 'label' => "node 1", 'father' => '2' ), 9 => array( 'label' => "node 2", 'father' => '2' ), 10 => array( 'label' => "node 3", 'father' => '2' ), 11 => array( 'label' => "I", 'father' => '9' ), 12 => array( 'label' => "II", 'father' => '9' ), 13 => array( 'label' => "III", 'father' => '9' ), 14 => array( 'label' => "IV", 'father' => '9' ), 15 => array( 'label' => "V", 'father' => '9' ), ); 

用法:函数需要$ a(数组),$ parent_key(保存父亲的id的列的名称),$ children_key(孩子将要移动的列的名称)。 它什么都没有返回(数组通过引用被改变)。 例:

 treeze( $ARRAY, 'father', 'children' ); echo "<pre>"; print_r( $ARRAY ); 

一种方法是使用recursion函数,首先find列表的所有底部值,并将它们添加到新的数组中。 然后,对于每个新的ID,你使用相同的函数在该ID,采取返回的数组,并填充它在该项目的新儿童数组。 最后,你返回你的新arrays。

我不会为你做所有的工作,但函数的参数如下所示:

函数recursiveChildren($ items_array,$ parent_id = 0)

从本质上讲,它会find所有的父母为0的,然后对于每一个它会find所有的那些与该ID作为父母,并为每一个这样的。

最终的结果应该是你在找什么。

 //if order by parentid, id $arr = array( array('id'=>100, 'parentid'=>0, 'name'=>'a'), array('id'=>101, 'parentid'=>100, 'name'=>'a'), array('id'=>102, 'parentid'=>101, 'name'=>'a'), array('id'=>103, 'parentid'=>101, 'name'=>'a'), ); $arr_tree = array(); $arr_tmp = array(); foreach ($arr as $item) { $parentid = $item['parentid']; $id = $item['id']; if ($parentid == 0) { $arr_tree[$id] = $item; $arr_tmp[$id] = &$arr_tree[$id]; } else { if (!empty($arr_tmp[$parentid])) { $arr_tmp[$parentid]['children'][$id] = $item; $arr_tmp[$id] = &$arr_tmp[$parentid]['children'][$id]; } } } unset($arr_tmp); echo '<pre>'; print_r($arr_tree); echo "</pre>"; 

这三种传球方法有什么理由不起作用吗? 我没有做任何testing来比较一些recursion解决scheme的速度,但似乎更加困难。 如果您的初始数组已经与作为键的ID关联,那么您可以跳过第一个foreach()。

 function array_tree(&$array) { $tree = array(); // Create an associative array with each key being the ID of the item foreach($array as $k => &$v) $tree[$v['id']] = &$v; // Loop over the array and add each child to their parent foreach($tree as $k => &$v) { if(!$v['parent']) continue; $tree[$v['parent']]['children'][] = &$v; } // Loop over the array again and remove any items that don't have a parent of 0; foreach($tree as $k => &$v) { if(!$v['parent']) continue; unset($tree[$k]); } return $tree; }