在PHP中从平面数组构建树

在PHP中从平面数组构建树,php,arrays,tree,flat,Php,Arrays,Tree,Flat,我在网上到处找了找,还没找到我要找的东西。我有一个平面数组,每个元素都包含一个“id”和一个“parent_id”。每个元素只有一个父元素,但可能有多个子元素。如果父项id=0,则将其视为根级项。我想把我的平面阵列放到树上。我发现的其他示例仅将元素复制到父元素,但原始元素仍然存在 编辑 起始数组的每个元素都从单独的XML文件中读取。如果文件本身没有父项,则其父项id的值将为“0”。键实际上是字符串 我很抱歉刚才的混乱。希望这更清楚: /EDIT 我的起始阵列: Array ( [_319

我在网上到处找了找,还没找到我要找的东西。我有一个平面数组,每个元素都包含一个“id”和一个“parent_id”。每个元素只有一个父元素,但可能有多个子元素。如果父项id=0,则将其视为根级项。我想把我的平面阵列放到树上。我发现的其他示例仅将元素复制到父元素,但原始元素仍然存在

编辑

起始数组的每个元素都从单独的XML文件中读取。如果文件本身没有父项,则其父项id的值将为“0”。键实际上是字符串

我很抱歉刚才的混乱。希望这更清楚:

/EDIT

我的起始阵列:

Array ( [_319_] => Array ( [id] => 0 [parent_id] => 0 ) [_320_] => Array ( [id] => _320_ [parent_id] => 0 ) [_321_] => Array ( [id] => _321_ [parent_id] => _320_ ) [_322_] => Array ( [id] => _322_ [parent_id] => _321_ ) [_323_] => Array ( [id] => _323_ [parent_id] => 0 ) [_324_] => Array ( [id] => _324_ [parent_id] => _323_ ) [_325_] => Array ( [id] => _325_ [parent_id] => _320_ ) ) 排列 ( [[u319]=>阵列 ( [id]=>0 [parent_id]=>0 ) [\u 320][=>阵列 ( [id]=>\u 320_ [parent_id]=>0 ) [\u 321][=>阵列 ( [id]=>\u 321_ [家长id]=>\u 320_ ) [\u 322][=>阵列 ( [id]=>\u 322_ [家长id]=>\u 321_ ) [\u 323][=>阵列 ( [id]=>\U 323_ [parent_id]=>0 ) [[u324]=>阵列 ( [id]=>\u 324_ [家长id]=>\u 323_ ) [\u 325][=>阵列 ( [id]=>\U 325_ [家长id]=>\u 320_ ) ) 生成树后生成的数组:

Array ( [_319_] => Array ( [id] => _319_ [parent_id] => 0 ) [_320_] => Array ( [id] => _320_ [parent_id] => 0 [children] => Array ( [_321_] => Array ( [id] => _321_ [parent_id] => _320_ [children] => Array ( [_322_] => Array ( [id] => _322_ [parent_id] => _321_ ) ) ) [_325_] => Array ( [id] => _325_ [parent_id] => _320_ ) ) [_323_] => Array ( [id] => _323_ [parent_id] => 0 [children] => Array ( [_324_] => Array ( [id] => _324_ [parent_id] => _323_ ) ) ) 排列 ( [[u319]=>阵列 ( [id]=>\U 319_ [parent_id]=>0 ) [\u 320][=>阵列 ( [id]=>\u 320_ [parent_id]=>0 [子项]=>数组 ( [\u 321][=>阵列 ( [id]=>\u 321_ [家长id]=>\u 320_ [子项]=>数组 ( [\u 322][=>阵列 ( [id]=>\u 322_ [家长id]=>\u 321_ ) ) ) [\u 325][=>阵列 ( [id]=>\U 325_ [家长id]=>\u 320_ ) ) [\u 323][=>阵列 ( [id]=>\U 323_ [parent_id]=>0 [子项]=>数组 ( [[u324]=>阵列 ( [id]=>\u 324_ [家长id]=>\u 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; } 函数构建树(数组&$elements,$parentId=0){ $branch=array(); foreach($elements作为$element){ if($element['parent_id']==$parentId){ $children=$this->buildTree($elements,$element['id']); if(儿童){ $element['children']=$children; } $branch[]=$element; } } 返回$branch; }
我可以看到逻辑,除了结果中的这一点:

Array
(
    [0] => Array
        (
            [id] => 0
            [parent_id] => 0
        )

    [1] => Array
        (
            [id] => 1
            [parent_id] => 0
        )
IMHO,父项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);

因为您滥用了0作为根的“神奇”数字和现有id,我们现在在id=0分支中有了递归。在
之前添加
如果($item['parent\u id'!=$item['id'])
$tree[$item['parent\u id']['children'][=&$tree[$item['id']];
可以防止这种情况发生,但它并不漂亮。

可以构造稍微不同的源数组,您可以使用此函数(父id、id、标题):

$q=mysql\u查询(“从类别中选择id、父\u id、名称”);
而($r=mysql\u fetch\u row($q)){
$names[$r[0]]=$r[2];
$children[$r[0]][]=$r[1];
}
函数render_select($root=0,$level=-1){
全球$姓名,$儿童;
如果($root!=0)
回显“”。strrep(“”,$level)。$names[$root].';
foreach($children[$root]作为$child)
渲染_选择($child,$level+1);
}
回声';
渲染_选择();
回声';

  • 您希望在MySQL中存储和加载分层数据,因为我认为这可以解决一些问题

    看起来您正试图使用邻接模型将数据组织到层次结构中。还有其他方法可以使用嵌套实现此目的。如果您不是从数据库获取此数据,则这可能没有多大用处

    此链接应该可以帮助您:

    此链接适合我:

    $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);
    
    你忘了把
    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;
    }
    

    这是我的解决方案,如果我们假设顶级父级\u 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);
            }
        }
    }
    

    虽然这是一个老问题,但我将在这里发布我的答案:

    /* 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\u column
    是PHP5.5,但您可以轻松制作自己的。

    Firefly的解决方案正在发挥作用,但是,正如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 $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;
    }
    

    干净、短且无压舱物。阵列到树:

    class Mother {
        private $root;
        public function treeInit($array)
        {
            $this->root = new Child();
            foreach($array as $value){
                $this->root->treeClimb(array_reverse($value));
            }
            return $this->root;
        }
    }
    
    class Child {
        private $children = [];
        public function treeClimb($arr)
        {
            if(count($arr) > 0) {
                $childTmp = array_pop($arr);
                if(!key_exists($childTmp,$this->children))
                {
                    $this->children[$childTmp] = new Child();
                }
            $this->children[$childTmp]->treeClimb($arr);
            }
        }
    }
    
    $array = array(array('obst','banae','krumm','gelb'),
                        array('obst','beere','him'),
                        array('obst','beere','brom'),
                        array('obst','banae','gerade'),
                        array('veg','carot','gerade'));
    
    $obj = new Mother();
    var_dump($obj->treeInit($array));
    

    SteveEdson的代码运行良好,但在原始数据结构中不存在元素的父元素的情况除外


    我提出了一个类似于@eugen rieck的解决方案,并希望与大家分享。不过,我将我的索引数组命名为
    $branchs

    $tree = [];
    $branches = [];
    
    while (!empty($input)) {
        $beforeCount = count($input);
    
        foreach ($input as $id => $item) {
            $pid = $item['parent_id'];
    
            if (isset($branches[$pid])) {
                $branches[$pid]['children'][$id] = $item;
                $branches[$id] = &$branches[$pid]['children'][$id];
                unset($input[$id]);
            }
        }
    
        if ($beforeCount === count($input)) {
            $firstItem = array_shift($input);
            $id = $firstItem['id'];
            $tree[$id] = $firstItem;
            $branches[$id] = &$tree[$id];
        }
    }
    
    这是我的解决方案
    function buildTree(array &$elements, $parentId = 0)
    {
        $branch = array();
        foreach ($elements as &$element) {
            if ($element["parent_id"] != null && $elements[$element["parent_id"]] == null)
                unset($element["parent_id"]);        
            if ($element['parent_id'] == $parentId) {
                $children = buildTree($elements, $element['id']);
                if ($children) {
                    $element['children'] = $children;
                }
                $branch[$element['id']] = $element;
                unset($element);
            }
        }
        return $branch;
    }
    
    $tree = [];
    $branches = [];
    
    while (!empty($input)) {
        $beforeCount = count($input);
    
        foreach ($input as $id => $item) {
            $pid = $item['parent_id'];
    
            if (isset($branches[$pid])) {
                $branches[$pid]['children'][$id] = $item;
                $branches[$id] = &$branches[$pid]['children'][$id];
                unset($input[$id]);
            }
        }
    
        if ($beforeCount === count($input)) {
            $firstItem = array_shift($input);
            $id = $firstItem['id'];
            $tree[$id] = $firstItem;
            $branches[$id] = &$tree[$id];
        }
    }