使用PHP从数组构建多维数组

6
我希望建立一个多维数组,基于一个数组。例如,我想要:
$test = array (
0 => 'Tree',
1 => 'Trunk',
2 => 'Branch',
3 => 'Limb',
4 => 'Apple',
5 => 'Seed'
);

成为
$test = 
array (
   'Tree' => array (
       'Trunk' => array (
           'Branch'  => array (
               'Limb'  => array (
                   'Apple'  => array (
                       'Seed' => array ()
                   )
               )
           )
       )
   )
);

更简单的说法是:
$result[Tree][Trunk][Branch][Limb][Apple][Seed] = null;

我试图使用递归函数来实现这个,但是我遇到了内存限制的问题,所以显然我做错了。

<?php
$test = array (
0 => 'Tree',
1 => 'Trunk',
2 => 'Branch',
3 => 'Limb',
4 => 'Apple',
5 => 'Seed'
);



print_r($test);





print "results of function";

print_r(buildArray($test));



function buildArray (&$array, &$build = null)
{
    if (count($array) > 0)
    {

        //create an array, pass the array to itself removing the first value



        $temp = array_values($array);   
        unset ($temp[0]);           
        $build[$array[0]] =  $temp;


        buildArray($build,$temp);



        return $build;
    }

    return $build;


}

这是一个很好的例子,说明为什么递归大多数情况下并不是一个好主意。通常情况下,取消递归非常容易,并且这样做可以获得通常更快、占用空间更少、更易于理解的代码。 - John Cartwright
4个回答

8
这里有一个使用foreach而不使用递归的方法,可以实现相同的功能:
function buildArray($array)
{
    $new = array();
    $current = &$new;
    foreach($array as $key => $value)
    {
        $current[$value] = array();
        $current = &$current[$value];
    }
    return $new;
}

[ 演示 ]

现在你的函数...首先,没有先定义为数组的情况下使用$build[$array[0]]会产生E_NOTICE。 其次,你的函数进入了无限递归,因为你实际上没有修改$array$temp不同),所以count($array) > 0将永远为真。
即使你正在修改$array,你也不能再使用$array[0],因为你取消了它,索引不会自动上移。你需要使用array_shift
之后,你将$build$temp传递给你的函数,这将导致进一步的问题,因为你现在将$build分配给$temp,因此在已经无限循环的循环中创建了另一个循环。

我试图在你的代码中修复所有这些问题,但最终意识到我的代码现在基本上与Pevara的答案完全相同,只是变量名不同,所以...就这样吧。


2
这个函数是递归执行的,非常有效:
function buildArray($from, $to = []) {  
    if (empty($from)) { return null; }
    $to[array_shift($from)] = buildArray($from, $to);
    return $to;
}

在您的代码中,我预计会看到一个错误。在第一次迭代中,您正在与$build通信,就好像它是一个数组,而实际上您已将其默认为null


2

看起来很简单

$res = array();
$i = count($test);
while ($i) 
    $res = array($test[--$i] => $res);
var_export($res);

返回

array ( 'Tree' => array ( 'Trunk' => array ( 'Branch' => array ( 'Limb' => array ( 'Apple' => array ( 'Seed' => array ( ), ), ), ), ), ), )

有一个有趣的解决方案,不使用指针。虽然不是最有效的方案。 - John Cartwright
@JohnCartwright 为什么这比调用函数效率低? - splash58
这与函数无关,而是涉及到创建副本与引用。 - John Cartwright
@JohnCartwright 你写道“不是最有效率的。” 我的代码哪里不够高效呢?只是好奇。 - splash58
我正在描述微小的优化,但根据数量的不同,它可能会增加相当多的时间和内存。通过创建变量的副本,您依赖于PHP来为变量副本分配内存。引用通过简单地引用现有分配的内存而工作方式不同。随着数量的增加,您分配的内存越多,您将更多地依赖垃圾收集器运行。尽管如此,这还是稍微简化了一些。 - John Cartwright
显示剩余2条评论

0
使用指针,不断地将其指向更深的位置。你的两个输出示例分别给出了最深层次的值为array()null;如果你想要得到null,可以将$p[$value] = array();替换为$p[$value] = $test ? array() : null;
$test = array(
    'Tree',
    'Trunk',
    'Branch',
    'Limb',
    'Apple',
    'Seed'
);

$output = array();
$p = &$output;
while ($test) {
    $value = array_shift($test);
    $p[$value] = array();
    $p = &$p[$value];
}
print_r($output);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接