在PHP中将单个数组转换为多维数组

5

如果我尝试解决一个问题几个小时了,但是却找不到解决方案。

如果有一个路径的单一数组

$singleArray = array(
   '/Web',
   '/Web/Test1',
   '/Web/Test2', 
   '/Web/Test2/Subfolder',
   '/Web/Test3',
   '/Public'
);

我希望从这个数组中创建一个多维数组,保留键名并将子文件夹放在正确的父文件夹中。稍后我想循环遍历新数组以创建文件夹树(但这不是问题)。

新数组应该长这样:

$multiArray = array(
   '/Web'=>array(
      '/Web/Test1'=>array(),
      '/Web/Test2'=>array(
          '/Web/Test2/Subfolder'=>array()
      ),
      '/Web/Test3'=>array()
   ),
   '/Public'=>array()
);

我没有投票,但这是一个询问涉及逻辑步骤的问题吗?还是仅仅是要求为OP编写代码的请求? - Micaiah Wallace
一个好的答案会给出逻辑,并可能使用代码来解释(因为它比伪代码或流程图更易于查看)。 - jcuenod
我不知道你们在抱怨什么。这是一个合法的问题。答案可以用伪代码表示,你知道的。 - Andrei
@OIS:我已经尝试了很多方法。从调用递归函数,通过展开每个元素的字符串来构建数组的每个部分。但我已经卡在了第二维度,其中还包含“/Web/Test2/Subfolder”等其他解决方案,我已经记不起来了。SnoApps:我正在寻找所涉及的逻辑步骤,而不是完整的解决方案(即使下面的答案也是如此)。抱歉,我是新手。下次有问题时,我会尽量提出更完整的问题(尽管我的英语不是很好...)。 - devops21212
2个回答

5
以下代码将创建你想要的数组。解决你问题的关键是在每次迭代中创建对该数组的引用。
<?php
$singleArray = array(
    '/Web',
    '/Web/Test1',
    '/Web/Test2',
    '/Web/Test2/Subfolder',
    '/Web/Test3',
    '/Public'
);

$multiArray = array();

foreach ($singleArray as $path) {
    $parts       = explode('/', trim($path, '/'));
    $section     = &$multiArray;
    $sectionName = '';

    foreach ($parts as $part) {
        $sectionName .= '/' . $part;

        if (array_key_exists($sectionName, $section) === false) {
            $section[$sectionName] = array();
        }

        $section = &$section[$sectionName];
    }
}

非常感谢。这个工作像魅力一样。我想我的问题是,我没有正确理解引用。我认为我必须深入研究有关此事的文档和教程。但首先,我将尝试调试代码以了解这里发生了什么;) - devops21212
不错的解决方案,我更喜欢使用递归函数而不是你的内部foreach - jcuenod

1

搞定了!很棒的挑战!

首先,我按文件夹数量对数组进行排序,以便首先处理具有最少文件夹(在根目录中)的项目。

然后,函数遍历每个数组项和该项中的每个文件夹,将其与数组中现有的项目进行比较,如果存在,则将其作为多维数组放置在该项中。

这适用于最多两个子文件夹 - /root/sub1/sub2 - 但是添加更深层次的功能也很简单。

此示例代码还打印出了处理前/处理后的数组:

$singleArray = array(
   '/Web',
   '/Web/Test1',
   '/Web/Test2', 
   '/Web/Test2/Subfolder',
   '/Web/Test3',
   '/Public'
);


echo "<pre>";
print_r($singleArray);

$multiArray = array();


//first sort array by how many folders there are so that root folders are processed first
usort($singleArray, function($a, $b) {

    $a_folders = explode("/", $a);
    $b_folders = explode("/", $b);

    $a_num = count($a_folders); //number of folders in first
    $b_num = count($b_folders); //number of folders in second

    if($a_num > $b_num) return -1;
    elseif($a_num < $b_num) return 1;
    else return 0;

});

//foreach in array
foreach($singleArray as $item){

    //get names of folders
    $folders = explode("/", $item);

    //if the first folder exists
    if(in_array($folders[0], $multiArray)){

        $key1 = array_search($folders[0], $multiArray);

        //repeat for subfolder #1
        if(in_array($folders[1], $multiArray[$key1])){

            $key2 = array_search($folders[1], $multiArray[$key1]);

            //repeat for subfolder #2
            if(in_array($folders[2], $multiArray[$key1][$key2])){

                $key3 = array_search($folders[2], $multiArray[$key1][$key2]);

                array_push($multiArray[$key1][$key2][$key3], $item);

            } else array_push($multiArray[$key1][$key2], $item);

        } else array_push($multiArray[$key1], $item);

    } else array_push($multiArray, $item);

}

//reverse the array so that it looks nice
$multiArray = array_reverse($multiArray);

print_r($multiArray);

这将输出:
Array
(
    [0] => /Web
    [1] => /Web/Test1
    [2] => /Web/Test2
    [3] => /Web/Test2/Subfolder
    [4] => /Web/Test3
    [5] => /Public
)
Array
(
    [0] => /Web
    [1] => /Public
    [2] => /Web/Test1
    [3] => /Web/Test2
    [4] => /Web/Test3
    [5] => /Web/Test2/Subfolder
)

谢谢你的回答。说实话,我之前有一个相似的解决方案。但正如你所指出的:它只适用于第二个子文件夹。但我会尝试使用你的代码并进行调整以使用更多的子文件夹 ;) - devops21212

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