所以我有以下内容:
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
)
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
}
}
}
答案 0 :(得分:1)
这是一个“多路”树,其中“数据”存储在节点上。
除非源数组有序,否则'父'节点位于'子'节点之前,如果只使用一个传递,则树将无法正确构建。
此版本的代码在尝试插入子代时会执行多次传递。
为减少阵列扫描量,保留单独的节点列表( $ sourceKeys ),并从列表中删除任何插入的节点。
像往常一样:Working code at Eval.in - 和 - Full source code at Pastebin.com
Todo:测试这对于大树有多贵(可能是为了更新?)
尝试插入一个节点的功能......
/**
* 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),
);