递归迭代数组并根据它的“路径”创建一个数组

时间:2016-07-07 23:18:41

标签: php arrays recursion iterator

我很难弄清楚如何递归迭代数组并创建一个数组的“路径”

我有两个数组。一个是目录树的数组,看起来像这样:

$directoryTree = [

    'accounting' => [

        'documents' => [
        ],

        'losses' => [
        ],

        'profit' => [
        ]               

    ],
    'legal' => [

        'documents' => [
        ]
    ]
];

另一个是文件列表,用于指定文件应驻留在哪个目录“path”:

$fileList = [

    [
        'name' => 'Overview.doc',
        'dir_path' => []
    ],

    [
        'name' => 'Incorporation.doc',
        'dir_path' => []
    ],  

    [
        'name' => 'Profit And Loss.xls',
        'dir_path' => ['accounting']
    ],

    [
        'name' => 'Profit 1.xls',
        'dir_path' => ['accounting', 'profit']
    ],

    [
        'name' => 'Loss 1.xls',
        'dir_path' => ['accounting', 'losses']
    ],

    [
        'name' => 'TOS Draft.doc',
        'dir_path' => ['legal', 'documents']
    ]

    [
        'name' => 'Accounting Doc.pdf',
        'dir_path' => ['accounting', 'documents']
    ],      
];

基本上我要做的是遍历$directoryTree并查看$fileList中是否有任何元素,其中包含迭代器所在的“路径”。如果有元素应该添加在那里。

最终数组应该类似于this

$finalOutput = [
    'accounting' => [

        'documents' => [
            'Accounting Doc.pdf'
        ],

        'losses' => [
            'Loss 1.xls'
        ],

        'profit' => [
            'Profit 1.xls'
        ],

        'Profit And Loss.xls'

    ],
    'legal' => [

        'documents' => [
            'TOS Draft.Doc'
        ]
    ],

    'Overview.doc',
    'Incorporation.doc',

];

我还包括这张图片只是为了进一步澄清: array map

我所做的尝试并没有让我走得太远。我一直试图以递归方式遍历数组而陷入困境,并且不确定如何解决下一个问题。

3 个答案:

答案 0 :(得分:1)

以下代码应该可以解决问题。考虑一下伪代码。它真的是javascript,java和单词的组合哈哈。

@stck是一个字符串数组,跟踪路径

//function should return an empty $fileList signaling all files have been processed
function treeTraversal($directoryTree, $fileList, stck) {

    //begins by processing all the files that are children of the root directory 
    //e.g. those with dir_name =[]
    //removes them from $fileList so we don't have to keep iterating over them
    if(stck.length == 0) {// == 0 only once, when processing first child of root
        for(var i = 0; i < $fileList.length; i ++) {
            if($fileList[i].dir_name.length == 0) {
                $directoryTree.push($fileList[i]);
                $fileList.removeElementAtIndex(i)
            }
        }
    }

    // now recursively traverse the tree. Record the path in var called stck
    for(var i = 0; i < $directoryTree.length; i++) {
        stck.push($directoryTree[i]); // $directoryTree[i] refers to name of directory not its contents
        if($directoryTree[i] is array)
            $fileList = treeTraversal($directoryTree[i], $fileList, stck);
    for(var j = 0; j < $fileList.length; j++) {
        if($fileList[j].dir_path == stck) {
            $directoryTree.push($fileList[j]);
            $fileList.removeElementAtIndex(j);
        }
    }
    stck.pop();
    return $fileList
}

答案 1 :(得分:1)

更难以迭代$fileList并将它们放在正确的目录数组下吗? e.g。

$finalOutput = $directoryTree;
foreach ($fileList as $file) {
    $current_dir &= $finalOutput;
    foreach ($file['dir_path'] as $dir) {
        if (isset($current_dir[$dir])) {
            $current_dir &= $current_dir[$dir];
        } else {
            $current_dir = null;
            break;
        }
    }
    if (is_array($current_dir)) {
        $current_dir[] = $file['name'];
    } else {
        // do you want to do anything if dir is not there?
    }
}

注意:我没有运行代码,但应该知道它是如何工作的。

如果由于某些未说明的原因,您必须反复遍历$directoryTree,那么您应该小心确保逻辑在O(n)(或其附近)而不是O(n^2)时间运行。一个简单的算法如下:

  • 浏览$fileList并生成所有目录的地图 - &gt;文件
  • 现在浏览$directoryTree并填写地图中的文件

答案 2 :(得分:0)

有趣的问题。我的答案实际上没有按照&#34;怎么做&#34;来回答这个问题,但它表明,一旦可以更容易地解决复杂问题,你需要把它复杂化,可能这些小解决方案可以在以后重复使用。

基本上,您需要能够设置&#34;嵌套键&#34;的值。我遇到了questions(并亲自面对)关于获取&#34;嵌套键&#34;的值。

所以我决定实现隐藏递归的数组访问类,并帮助使用类似数组的键来获取嵌套值。您可以查看repo。对代码的解释实际上符合问题的范畴,但由于时间很长,我无法在此解释。重点是数组访问方法隐藏了递归。

鉴于此课程,您的问题可以简化为$directoryTree = new CompositeKeyArray($directoryTree); foreach ($fileList as $file) { if ( !empty($file['dir_path']) && !isset($directoryTree[$file['dir_path']]) ) { throw new Exception; } array_push($file['dir_path'], []); $directoryTree[$file['dir_path']] = $file['name']; } var_dump($directoryTree->toArray()); 上的简单循环:

add

在其中一条评论中,您提到过您希望在不存在的路径上抛出异常。 if部分处理这个。

这是working demo