簡體   English   中英

遞歸函數從數組創建文件夾樹

[英]Recursive function to create a folder tree from array

所以我有以下幾點:

id           => the id of the folder
name         => the name of the folder
folder_id    => null if it's in the root, but will have the "id" of it's parent if it's inside another folder

我將所有這些列在數組中,如下所示$folder_array在我的示例中為$folder_array

Array (
    [1] => Array (
        [name] => folder1
        [id] => 1
        [folder_id] => null
    )
    [2] => Array (
        [name] => folder2
        [id] => 2
        [folder_id] => null
    )
    [3] => Array (
        [name] => folder3
        [id] => 3
        [folder_id] => 2
    )
    [4] => Array (
        [name] => folder4
        [id] => 4
        [folder_id] => 3
    )
}

我正在嘗試制作一個具有各種文件夾樹的數組,所以我希望它看起來像:

Array (
    [1] => Array (
        [name] => folder1
        [id] => 1
        [folder_id] => null
    )
    [2] => Array (
        [name] => folder2
        [id] => 2
        [folder_id] => null,
        [children] => Array (
            [3] => Array (
                [name] => folder3
                [id] => 3
                [folder_id] => 2,
                [children] => Array (
                    [4] => Array (
                        [name] => folder4
                        [id] => 4
                        [folder_id] => 3
                    )
                )
            )
        )
    )
}

到目前為止,我可以將第一級文件夾放入正確的子級數組中,但是我很難進入多個級別。

任何人都可以幫助我修復此代碼,以便制作出有效的文件夾樹。 而且,如果有人有任何更有效的組織方式,我也會對此持開放態度。

到目前為止,這是我的代碼:

$folder_array = array(
    "1" => array("name"=> "folder1","id" => "1","folder_id" => null),
    "2" => array("name"=> "folder2","id" => "2","folder_id" => null),
    "3" => array("name"=> "folder3","id" => "3","folder_id" => "2"),
    "4" => array("name"=> "folder4","id" => "4","folder_id" => "3")
);

//a new array to store the folder tree in
$new_array = array();

//now search through each one that has no folder_id
foreach($folder_array as $folder)
{
    //if the folder id is empty, it means it is in the root(home) folder
    if(empty($folder['folder_id']))
    {
        $new_array[$folder['id']] = $folder_form_array[$folder['id']];

        //now go through folder_array again and see if it has any folders inside that one
        foreach($folder_array as $folder2)
        {
            //..and so on
        }
    }
}

這是一個“多路”樹,其中“數據”存儲在節點上。

除非源數組是有序的,否則“父”節點先於“子”節點,否則如果僅使用一次傳遞,則樹將無法正確構建。

嘗試插入子代時,此版本的代碼將進行多次傳遞。

為了減少陣列掃描的數量,保留了一個單獨的節點列表( $ sourceKeys ),並且從該列表中刪除了所有插入的節點。

與往常一樣: Eval.in上的工作代碼 -和Pastebin.com上的 完整源代碼

待辦事項:測試這對於大樹有多昂貴(也許需要更新嗎?)

試圖插入一個節點的函數...

/**
 * Insert:  Find the 'parent' node
 *          if child not found then insert a 'node'
 *
 * @param array node passed by reference as the new node will be inserted
 * @param integer $parentId - root Id - may be null it indicate a 'root'
 * @param integer $childId
 * @param array   $folderInfo - the 'node data' to be stored

 * @return boolean  true if parentId found and child alive
 *                   false if parent not found anywhere in the tree
 */
function insertNode(&$node, $parentId, $childId, $folderInfo) {

    // is Root Node
    if (is_null($parentId)) {
        $node[$childId] = $folderInfo;
        $node[$childId]['children'] = array();
        return true;
    }

    if (isset($node[$parentId])) { // this node will be processed
        if (!isset($node[$parentId]['children'][$childId])) {
            $node[$parentId]['children'][$childId] = array_merge($folderInfo,
                                           array('children' => array())); // add child node
            return true;
        }
        return true; // end of processing
    }

    // check all the children of this node...
    foreach($node as $idx => &$child) { // need the reference
        if (count($child['children']) >= 1) { // check the children...
            if (insertNode($child['children'], $parentId, $childId, $folderInfo)) {
                return true;
            }
        }
    }
    return false; // parentId not in the tree
}

開始處理數據...

// extract the root nodes as we need those first...
$roots = array_filter($source, function($data) {
                                  return is_null($data['folder_id']);
                               });

// we need a list of child nodes that haven't been added yet
$sourceKeys = array_diff(array_keys($source), array_keys($roots));

初始化輸出樹並處理根節點...

$theTree = array();

// first we need to insert the roots... worth doing as a separate pass...
foreach($roots as  $idx => $folderInfo) {
    insertNode($theTree, $folderInfo['folder_id'], $folderInfo['id'], $folderInfo);
}

現在處理需要添加的“子節點”列表...

// now we do multiple passes down the source trying to insert nodes.
// We know we have finished when nothing is inserted during the pass.

// for efficiency, we will drive off the sourceKeys array after removing
// any inserted entries...

do {
    $insertCount = 0;

    foreach($sourceKeys as $position => $idx) {

        $folderInfo = $source[$idx];
        $inserted = insertNode($theTree, $folderInfo['folder_id'], $folderInfo['id'], $folderInfo);
        if ($inserted) {
            $insertCount++;
            unset($sourceKeys[$position]); // it is safe to do this in 'foreach'
        }
    }

} while ($insertCount > 0);

我們完成了...只是要做一些報告...

// report nodes not inserted... this may be useful
foreach($sourceKeys as $idx) {
        var_dump('not inserted:', $source[$idx]);
}

// output the tree
echo '<pre>', 'Children are in the same order as the input array.', '<br />';
    print_r($theTree);
echo '</pre>';
exit;

測試數據-注意:隨機順序和一個無效節點(666)。

$source = Array (
   4 =>   Array("name" => "folder4",   "id" => 4,   "folder_id" => 3),
   11 =>  Array("name" => "folder11",  "id" => 11,  "folder_id" => 3),
   13 =>  Array("name" => "folder13",  "id" => 13,  "folder_id" => 12),
   31 =>  Array("name" => "folder31",  "id" => 31,  "folder_id" => 99),
   12 =>  Array("name" => "folder12",  "id" => 12,  "folder_id" => 98),
   42 =>  Array("name" => "folder42",  "id" => 42,  "folder_id" => 32),
   32 =>  Array("name" => "folder32",  "id" => 32,  "folder_id" => 99),
   666 => Array("name" => "folder666", "id" => 666, "folder_id" => 9999),
   99 =>   Array("name" => "folder99Root",   "id" => 99,   "folder_id" => null),
   3 =>   Array("name" => "folder3",   "id" => 3,   "folder_id" => 98),
   33 =>  Array("name" => "folder33",  "id" => 33,  "folder_id" => 99),
   98 =>   Array("name" => "folder98Root",   "id" => 98,   "folder_id" => null),
);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM