如何从平面数组构建具有无限深度的嵌套 HTML 列表? [英] How can I build a nested HTML list with an infinite depth from a flat array?
问题描述
我正在尝试从格式如下的源数组生成多级 HTML 列表:
/*** id = 唯一 id* parent_id = "id" 表示此项直接嵌套在其下* text = 输出字符串*/$list = 数组(大批('id' =>1、'parent_id' =>0,'文本' =>'1级',), 大批('id' =>2、'parent_id' =>0,'文本' =>'级别 2',), 大批('id' =>3、'parent_id' =>2、'文本' =>'级别 2.1',), 大批('id' =>4、'parent_id' =>2、'文本' =>'级别 2.2',), 大批('id' =>5、'parent_id' =>4、'文本' =>'级别 2.2.1',), 大批('id' =>6、'parent_id' =>0,'文本' =>'级别 3',));
目标是具有无限深度的嵌套
.上面数组的预期输出是这样的:
- Level 1
- Level 2
- Level 2.1
- Level 2.2
- Level 2.2.1
ul>
如果只有数组项有一个名为 child
的键或包含实际子数组的东西,则很容易递归这些并使用如下函数获得所需的输出:
function makeList($list){echo '';foreach ($list 作为 $item){echo '- '.$item['text'];如果 (isset($item['child'])){makeList($item['child']);}echo '</li>';}回声'</ul>';}
不幸的是,我的情况并非如此 - 源数组的格式无法更改.所以,很久以前我写了这个非常讨厌的函数来实现它,它只能在三个级别上工作(代码是逐字粘贴的,带有原始注释).我知道阅读很长很无聊,请耐心等待:
function makeArray($links){//输出$nav = array();foreach ($links as $k => $v){//如果没有parent_id,我们可以假设它是一个顶级链接如果(空($v['parent_id'])){$id = isset($v['id']) ?$v['id'] : $k;$nav[$id] = $v;//从原数组中移除未设置($links[$k]);}}//再次循环剩余的链接,//我们可以假设它们都有一个 parent_idforeach ($links as $k => $v){//链接的parent_id在顶级数组中,所以这是一个二级链接//我们已经遍历了每个项目,所以我们知道它们都被考虑在内如果 (isset($nav[$v['parent_id']])){$id = isset($v['id']) ?$v['id'] : $k;//将其作为子项添加到顶级链接$nav[$v['parent_id']]['child'][$id] = $v;//设置一个标记,以便我们知道要循环添加第三级的标记$nav2[$id] = $v;//从数组中删除未设置($links[$k]);}}//第三级的最后一次迭代//此时所有其他链接都已从原始数组中删除foreach ($links as $k => $v){$id = isset($v['id']) ?$v['id'] : $k;//链接的parent_id在二级数组中,所以这是一个三级链接//孤儿将被忽略如果 (isset($nav2[$v['parent_id']])){//这部分很疯狂,随它去吧$nav3 = $nav2[$v['parent_id']]['parent_id'];$nav[$nav3]['child'][$v['parent_id']]['child'][] = $v;}}返回 $nav;}
这使得数组如下:
数组('文本' =>'1级''孩子' =>大批(大批('文本' =>'级别 1.2''孩子' =>大批(大批('文本' =>'级别 1.2.1''孩子' =>大批(//等等.),大批('文本' =>'级别 1.2.2''孩子' =>大批(//等等.),)))));
用法:
$nav = makeArray($links);makeList($nav);
<小时>
我花了很多空闲时间试图解决这个问题,我在这里给出的原始代码仍然是我能够生成的最佳解决方案.
如果没有那个糟糕的功能(深度限制为 3),并且有无限多个级别,我怎么能做到这一点?有没有更优雅的解决方案?
打印:
function printListRecursive(&$list,$parent=0){$foundSome = false;for( $i=0,$c=count($list);$i<$c;$i++ ){if( $list[$i]['parent_id']==$parent ){如果( $foundSome==false ){echo '';$foundSome = true;}echo '<li>'.$list[$i]['text'].'</li>';printListRecursive($list,$list[$i]['id']);}}如果( $foundSome ){回声'</ul>';}}printListRecursive($list);
创建多维数组:
function makeListRecursive(&$list,$parent=0){$result = array();for( $i=0,$c=count($list);$i<$c;$i++ ){if( $list[$i]['parent_id']==$parent ){$list[$i]['childs'] = makeListRecursive($list,$list[$i]['id']);$result[] = $list[$i];}}返回 $result;}$result = array();$result = makeListRecursive($list);echo '';var_dump($result);echo '</pre>';
I'm trying to produce a multi-level HTML list from a source array that is formatted like this:
/**
* id = unique id
* parent_id = "id" that this item is directly nested under
* text = the output string
*/
$list = array(
array(
'id' => 1,
'parent_id' => 0,
'text' => 'Level 1',
), array(
'id' => 2,
'parent_id' => 0,
'text' => 'Level 2',
), array(
'id' => 3,
'parent_id' => 2,
'text' => 'Level 2.1',
), array(
'id' => 4,
'parent_id' => 2,
'text' => 'Level 2.2',
), array(
'id' => 5,
'parent_id' => 4,
'text' => 'Level 2.2.1',
), array(
'id' => 6,
'parent_id' => 0,
'text' => 'Level 3',
)
);
The goal is a nested <ul>
with an infinite depth. The expected output of the array above is this:
- Level 1
- Level 2
- Level 2.1
- Level 2.2
- Level 2.2.1
- Level 3
If only the array items had a key called child
or something that contained the actual sub-array, it would be easy to recurse though these and get the desired output with a function like this:
function makeList($list)
{
echo '<ul>';
foreach ($list as $item)
{
echo '<li>'.$item['text'];
if (isset($item['child']))
{
makeList($item['child']);
}
echo '</li>';
}
echo '</ul>';
}
Unfortunately that's not the case for me - the format of the source arrays can't be changed. So, long ago I wrote this very nasty function to make it happen, and it only works up to three levels (code is pasted verbatim with original comments). I know it's a long boring read, please bear with me:
function makeArray($links)
{
// Output
$nav = array();
foreach ($links as $k => $v)
{
// If no parent_id is present, we can assume it is a top-level link
if (empty($v['parent_id']))
{
$id = isset($v['id']) ? $v['id'] : $k;
$nav[$id] = $v;
// Remove from original array
unset($links[$k]);
}
}
// Loop through the remaining links again,
// we can assume they all have a parent_id
foreach ($links as $k => $v)
{
// Link's parent_id is in the top level array, so this is a level-2 link
// We already looped through every item so we know they are all accounted for
if (isset($nav[$v['parent_id']]))
{
$id = isset($v['id']) ? $v['id'] : $k;
// Add it to the top level links as a child
$nav[$v['parent_id']]['child'][$id] = $v;
// Set a marker so we know which ones to loop through to add the third level
$nav2[$id] = $v;
// Remove it from the array
unset($links[$k]);
}
}
// Last iteration for the third level
// All other links have been removed from the original array at this point
foreach ($links as $k => $v)
{
$id = isset($v['id']) ? $v['id'] : $k;
// Link's parent_id is in the second level array, so this is a level-3 link
// Orphans will be ignored
if (isset($nav2[$v['parent_id']]))
{
// This part is crazy, just go with it
$nav3 = $nav2[$v['parent_id']]['parent_id'];
$nav[$nav3]['child'][$v['parent_id']]['child'][] = $v;
}
}
return $nav;
}
This makes an array like:
array(
'text' => 'Level 1'
'child' => array(
array(
'text' => 'Level 1.2'
'child' => array(
array(
'text' => 'Level 1.2.1'
'child' => array(
// etc.
),
array(
'text' => 'Level 1.2.2'
'child' => array(
// etc.
),
)
)
)
)
);
Usage:
$nav = makeArray($links);
makeList($nav);
I've spent many spare hours trying to work this out, and the original code which I have given here is still the best solution I've been able to produce.
How can I make this happen without that awful function (which is limited to a depth of 3), and have an infinite number of levels? Is there a more elegant solution to this?
Print:
function printListRecursive(&$list,$parent=0){
$foundSome = false;
for( $i=0,$c=count($list);$i<$c;$i++ ){
if( $list[$i]['parent_id']==$parent ){
if( $foundSome==false ){
echo '<ul>';
$foundSome = true;
}
echo '<li>'.$list[$i]['text'].'</li>';
printListRecursive($list,$list[$i]['id']);
}
}
if( $foundSome ){
echo '</ul>';
}
}
printListRecursive($list);
Create multidimensional array:
function makeListRecursive(&$list,$parent=0){
$result = array();
for( $i=0,$c=count($list);$i<$c;$i++ ){
if( $list[$i]['parent_id']==$parent ){
$list[$i]['childs'] = makeListRecursive($list,$list[$i]['id']);
$result[] = $list[$i];
}
}
return $result;
}
$result = array();
$result = makeListRecursive($list);
echo '<pre>';
var_dump($result);
echo '</pre>';
这篇关于如何从平面数组构建具有无限深度的嵌套 HTML 列表?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!