[英]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.