从数组列表创建数组树

Thu*_*ker 43 php arrays tree recursion

我有一个这样的列表:

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'),
)
Run Code Online (Sandbox Code Playgroud)

但是更大,所以我需要一种有效的方法将它变成像这样的结构树:

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',
    )
  )
)
Run Code Online (Sandbox Code Playgroud)

我不能使用像嵌套集或像becoas这样的东西,我可以在我的数据库中添加左右值.有任何想法吗?

Thu*_*ker 55

这就是我解决它的方式:

$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;
}
Run Code Online (Sandbox Code Playgroud)

  • 这很有效,只要确保,如果你有多个parentid = 0的项目,循环遍历所有项目并检查parentid == 0.如果这是真的,那么在该项目上运行createTree并将其附加到你的树阵.否则,此例程仅适用于parentid = 0的第一个项目 (2认同)
  • @JinIzzraeel如果你想通过ref传递非对象,你需要&符号.PHP中不鼓​​励递归. (2认同)

小智 40

如果你需要超过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;
}
Run Code Online (Sandbox Code Playgroud)


Vas*_*ily 15

还有一个Thunderstriker变体的返工 - 一个函数中的所有逻辑:

/**
 * @param $flatList - a flat list of tree nodes; a node is an array with keys: id, parentID, name.
 */
function buildTree(array $flatList)
{
    $grouped = [];
    foreach ($flatList as $node){
        $grouped[$node['parentID']][] = $node;
    }

    $fnBuilder = function($siblings) use (&$fnBuilder, $grouped, $idKey) {
        foreach ($siblings as $k => $sibling) {
            $id = $sibling['id'];
            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' => 'root'],
    ['id' => 101, 'parentID' => 100, 'name' => 'ch-1'],
    ['id' => 102, 'parentID' => 101, 'name' => 'ch-1-1'],
    ['id' => 103, 'parentID' => 101, 'name' => 'ch-1-2'],
];

$tree = buildTree($flat, 'parentID', 'id');
echo json_encode($tree, JSON_PRETTY_PRINT);
Run Code Online (Sandbox Code Playgroud)

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

  • 我喜欢这个例子,所以我把它包装在一个类中,并在github上提供它; https://github.com/srayner/NavTree (3认同)

Pie*_*NAY 9

以下是我对亚瑟修改的改编:

/* 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]);
}
Run Code Online (Sandbox Code Playgroud)

使用:

$tree = createTree($flat);
Run Code Online (Sandbox Code Playgroud)


Mar*_*chi 6

我创建了一个不寻常的('基于while'而不是递归)但多维排序函数,它可以遍历数组,直到没有任何孤儿.这里的功能:

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] );
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

建议:数组中每个元素的键必须是元素本身的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' ),
);
Run Code Online (Sandbox Code Playgroud)

用法:该函数需要$ a(数组),$ parent_key(保存父亲id的列的名称),$ children_key(子项将移动的列的名称).它什么都不返回(数组通过引用更改).例:

treeze( $ARRAY, 'father', 'children' );
echo "<pre>"; print_r( $ARRAY );
Run Code Online (Sandbox Code Playgroud)