在 PHP 中递归创建多维数组

Posted

技术标签:

【中文标题】在 PHP 中递归创建多维数组【英文标题】:Recursively creating a multi-dimensional array in PHP 【发布时间】:2010-12-08 03:50:32 【问题描述】:

我正在尝试找出编写 php 函数的最佳方法,该函数将从 mysql 表中递归地构建具有未知数量子级别的多维数组。它的目的是创建一个数据结构,可以循环创建网站上的导航菜单,每个菜单项可能有一个带有子菜单项的子菜单。

表中需要注意的字段有: 整数项目ID int ParentID varchar ItemText 文本项目链接 tinyint HasChildren

因此,函数返回的数组示例如下:

$menuItems = 大批( 项目ID# => 大批( 'ItemText' => '首页', 'ItemLink' => 'index.php', '儿童' => 数组( itemID# => 数组 ( 'ItemText' => 'Home Sub 1', 'ItemLink' => 'somepage.php', '儿童' => 0 ), itemID# => 数组 ( 'ItemText' => 'Home Sub 2', 'ItemLink' => 'somepage2.php', '儿童' => 0 ), ) ), 项目ID# => 大批( 'ItemText' => '联系方式', 'ItemLink' => 'contact.php', '儿童' => 0 ) ) );

如果有人能指出我完成此任务的正确方向,我将不胜感激。谢谢!

【问题讨论】:

【参考方案1】:

不太难。您所做的是将菜单项存储在一个数组中,您可以在其中通过 ID 查找它们。然后遍历菜单项,如果它们具有非空 ParentID,则将它们添加到其父项的子项列表中。然后从主列表中删除所有子项,这样就只剩下***项了。

代码:

<?php
$menuItems = array
(
    1 => array
    (
        'ItemText' => 'Home',
        'ItemLink' => 'index.php',
        'ParentID' => null,
    ),

    2 => array
    (
        'ItemText' => 'Home Sub 1',
        'ItemLink' => 'somepage.php',
        'ParentID' => 1,
    ),

    3 => array
    (
        'ItemText' => 'Home Sub 2',
        'ItemLink' => 'somepage2.php',
        'ParentID' => 1,
    ),

    4 => array
    (
        'ItemText' => 'Contact',
        'ItemLink' => 'contact.php',
        'ParentID' => null,
    ),
);

// Each node starts with 0 children
foreach ($menuItems as &$menuItem)
    $menuItem['Children'] = array();

// If menu item has ParentID, add it to parent's Children array    
foreach ($menuItems as $ID => &$menuItem)

    if ($menuItem['ParentID'] != null)
        $menuItems[$menuItem['ParentID']]['Children'][$ID] = &$menuItem;


// Remove children from $menuItems so only top level items remain
foreach (array_keys($menuItems) as $ID)

    if ($menuItems[$ID]['ParentID'] != null)
        unset($menuItems[$ID]);


print_r($menuItems);
?>

输出:

Array
(
    [1] => Array
        (
            [ItemText] => Home
            [ItemLink] => index.php
            [ParentID] => 
            [Children] => Array
                (
                    [2] => Array
                        (
                            [ItemText] => Home Sub 1
                            [ItemLink] => somepage.php
                            [ParentID] => 1
                            [Children] => Array
                                (
                                )

                        )

                    [3] => Array
                        (
                            [ItemText] => Home Sub 2
                            [ItemLink] => somepage2.php
                            [ParentID] => 1
                            [Children] => Array
                                (
                                )

                        )

                )

        )

    [4] => Array
        (
            [ItemText] => Contact
            [ItemLink] => contact.php
            [ParentID] => 
            [Children] => Array
                (
                )

        )

)

【讨论】:

这看起来正是我所需要的,我很感激约翰。只是为了确保我看对了,这个解决方案将适用于无限数量的子级别,对吧?看起来确实如此,只是确保我的示例数据只有一个子级别。 没关系,只是用一组更复杂的测试数据对其进行了测试,效果很好:) 这项工作完美无缺,效率极高。非常感谢你把它放在那里。【参考方案2】:

有一个函数,每次获取数组元素时都会调用自己。 如:

调用你的函数来显示一个节点。然后它检查它调用的节点是否有一个子菜单,如果有,它会再次调用它自己。并且这个过程一直重复,直到它消失,所有之前的函数调用都返回。

void printData($mysql_table_node)
    if($mysql_table_node.has_node())
        for($i = 0; $i < $mysqql_table_node.num_nodes())
            printData($mysql_table_node->own_node);
        
    
        return;

【讨论】:

我理解你的逻辑,但我认为你在解决方案中的抽象程度有点超出我的想象。我将如何创建这些节点对象以及检查节点对象是否具有节点的方法?如果我自己的问题是荒谬的,我深表歉意:) 一种简单的方法是在每个数据变量上设置标志。如果节点具有子级别,则标志将增加其具有子级别的次数。如果该数字大于 0,则其中包含子级别。【参考方案3】:

多维树和无序 html 列表生成器

    从多维数组递归构建。 从 (1) 生成多维 HTML 列表代码。

您永远无法知道给定项目列表中有多少维度。 每个元素可以有一个儿子->孙子->曾孙等等。

所以,你必须使用recursive function来生成一个多维列表。

代码如下:

<?php

$categories = array(
    '1'=>   array('name'=>'one','parent'=>null),
    '2'=>   array('name'=>'two','parent'=>null),
    '20'=>  array('name'=>'twenty','parent'=>'2'),
    '21'=>  array('name'=>'twenty one','parent'=>'2'),
    '210'=> array('name'=>'two hundred and ten',    'parent'=>'21'),
    '211'=> array('name'=>'two hundred and eleven', 'parent'=>'21'),
    '212'=> array('name'=>'two hundred and twelve', 'parent'=>'21')
);

$tree=Menu::CreateTree($categories);
print_r($tree);
Menu::GenerateMenuHtmlCode($tree);

class Menu
   
    public static function GenerateMenuHtmlCode($tree)
    
        echo '<ul>';
        foreach ($tree as $key=>$value)
        
             echo "<li>".$value['name'];
             if(!empty($value['sons'])) 
                 self::GenerateMenuHtmlCode($value['sons']);
             echo "</li>";
        
        echo '</ul>';
    

    public static function CreateTree($categories)
    
        $tree=array();
        self::AddElement(&$categories,&$tree,null);
        return $tree;
    

    private function AddElement($categories,&$tree,$parent)
    
        foreach ($categories as $key=>$value)
        
            if($value['parent']==$parent)
            
                $tree[$key]=$categories[$key];
                $tree[$key]['sons']=array();
                self::AddElement($categories,&$tree[$key]['sons'],$key);
            
            if(empty($tree['sons'])) unset ($tree['sons']);
        
        unset($categories[$parent]);
        return ;
    

?>

结果:

Array
(
    [1] => Array
        (
            [name] => one
            [parent] => 
            [sons] => Array()
        )

    [2] => Array
        (
            [name] => two
            [parent] => 
            [sons] => Array
                (
                    [20] => Array
                        (
                            [name] => twenty
                            [parent] => 2
                            [sons] => Array()
                        )

                    [21] => Array
                        (
                            [name] => twenty one
                            [parent] => 2
                            [sons] => Array
                                (
                                    [210] => Array
                                        (
                                            [name] => two hundred and ten
                                            [parent] => 21
                                            [sons] => Array()
                                        )

                                    [211] => Array
                                        (
                                            [name] => two hundred and eleven
                                            [parent] => 21
                                            [sons] => Array()
                                        )

                                    [212] => Array
                                        (
                                            [name] => two hundred and twelve
                                            [parent] => 21
                                            [sons] => Array()
                                        )
                                )
                        )
                )
        )
)

和:

<ul>
    <li>one</li>
    <li>two
        <ul>
            <li>twenty</li>
            <li>twenty one
                <ul>
                    <li>two hundred and ten</li>
                    <li>two hundred and eleven</li>
                    <li>two hundred and twelve</li>
                </ul>
            </li>
        </ul>
    </li>
</ul>

【讨论】:

【参考方案4】:

我知道这是一个迟到的回复,但我在上面找到了这个脚本,这太棒了。我遇到了一个问题,但由于 ItemID 的工作方式,当我使用与 OP 类似设计的表格运行它时,它让我的孩子不安。为了解决这个问题,并且考虑到大多数 Web 服务器中的 RAM 量应该能够处理这个问题,我采用了 John Kugelman's 很好的示例并稍微修改了它。我不必将子项应用于所有项目,然后再取消设置,而是创建一个新数组并将其全部构建在一起

代码:

$new_array = array();
foreach ($menuItems as $key => &$menuItem) 
    if (($menuItem['ParentID'] != NULL) && ($menuItem['ParentID'] != '')) 
        $new_array[$menuItem['ParentID']]['Children'][$menuItem['ItemID']] = &$menuItem;
     else 
        $new_array[$menuItem['ItemID']] = &$menuItem;
    


print_r($new_array);

希望这对其他人有所帮助,因为以上内容肯定对我有所帮助

【讨论】:

以上是关于在 PHP 中递归创建多维数组的主要内容,如果未能解决你的问题,请参考以下文章

php无限极分类递归写入多维数组的方法

php中多维数组的问题

php 多个多维数组求交集

js递归(二)——合并多维数组

使用递归函数获取多维php数组的新值和键

PHP 递归遍历文件夹到多维数组