所以,
问题
假设我们有具有以下结构的平面数组:
$array = [
['level'=>1, 'name' => 'Root #1'],
['level'=>1, 'name' => 'Root #2'],
['level'=>2, 'name' => 'subroot 2-1'],
['level'=>3, 'name' => '__subroot 2-1/1'],
['level'=>2, 'name' => 'subroot 2-2'],
['level'=>1, 'name' => 'Root #3']
];
问题是 - 转换该数组,使其成为一棵树。从属关系仅由元素 order 和level
field 确定。让我们定义children
为存储子节点的维度名称。对于上面的数组,它将是:
大批 ( 大批 ( '水平' => 1, '名称' => '根#1', ), 大批 ( '水平' => 1, '名称' => '根 #2', '孩子' => 大批 ( 大批 ( '级别' => 2, '名称' => '子根 2-1', '孩子' => 大批 ( 大批 ( '级别' => 3, '名称' => '__subroot 2-1/1', ), ), ), 大批 ( '级别' => 2, '名称' => '子根 2-2', ), ), ), 大批 ( '水平' => 1, '名称' => '根#3', ), )
如果不清楚谁是谁的父母,请进行更多说明:以下代码可以轻松地可视化想法:
function visualize($array)
{
foreach($array as $item)
{
echo(str_repeat('-', $item['level']).'['.$item['name'].']'.PHP_EOL);
}
}
visualize($array);
- 对于上面的数组:
-[根#1] -[根#2] --[子根 2-1] ---[__subroot 2-1/1] --[子根 2-2] -[根#3]
细节
所需的解决方案和输入数组都有一些限制:
- 输入数组始终有效:这意味着它的结构始终可以重构为树结构。没有负数/非数字级别,没有无效级别结构等奇怪的东西
- 输入数组可能很大,目前最大级别不受限制
- 解决方案必须通过单循环解决问题,因此我们不能将数组拆分为块,应用递归或以某种方式在数组内跳转。只是简单
foreach
(或另一个循环 - 没关系),只有一次,每个元素应该一个一个地处理。
我的方法
目前,我有堆栈的解决方案。我正在使用引用并维护堆栈的当前元素,将在当前步骤中写入该元素。那是:
function getTree(&$array)
{
$level = 0;
$tree = [];
$stack = [&$tree];
foreach($array as $item)
{
if($item['level']>$level) //expand stack for new items
{
//if there are child elements, add last to stack:
$top = key($stack);
if(count($stack[$top]))
{
end($stack[$top]);
$stack[] = &$stack[$top][key($stack[$top])];
}
//add ['children'] dim to top stack element
end($stack);
$top = key($stack);
$stack[$top]['children'] = [];
$stack[] = &$stack[$top]['children'];
}
while($item['level']<$level--) //pop till certain level
{
//two times: one for last pointer, one for ['children'] dim
array_pop($stack);
array_pop($stack);
}
//add item to stack top:
end($stack);
$stack[key($stack)][] = $item;
$level = $item['level'];
}
return $tree;
}
- 因为它足够长,所以我创建了一个使用和输出示例。
问题
如您所见,我的解决方案很长,它依赖于引用和数组内部指针处理(例如end()
),所以问题是:
可能有其他更短更清晰的方法来解决这个问题吗?它看起来像一些标准问题,但我没有找到任何相应的解决方案(有一个类似的问题- 但 OP 有确切的parent_id
从属关系,而我没有)