简体   繁体   English

在 PHP 中递归创建多维数组

[英]Recursively creating a multi-dimensional array in PHP

I am trying to figure out the best way to write a PHP function that will recursively build a multi-dimensional array with an unknown number of sublevels from a mysql table.我试图找出编写 PHP 函数的最佳方法,该函数将递归地构建一个多维数组,该数组具有来自 mysql 表的未知数量的子级别。 Its purpose is to create a data structure which can be looped through to create a navigation menu on a website, with each menu item possibly having a submenu with child menu items.它的目的是创建一个数据结构,可以通过循环创建一个网站上的导航菜单,每个菜单项可能有一个带有子菜单项的子菜单。

The fields of note in the table are:表中注意的字段是:
int ItemID内部项目ID
int ParentID内部父ID
varchar ItemText varchar 项目文本
text ItemLink文本项目链接
tinyint HasChildren tinyint HasChildren

So an example of a returned array from the function would be:因此,函数返回数组的示例是:

$menuItems = 
    array(
        itemID# => 
            array(
                'ItemText' => 'Home',
                'ItemLink' => 'index.php',
                'Children' => array(
                        itemID# => array (
                            'ItemText' => 'Home Sub 1',
                            'ItemLink' => 'somepage.php',
                            'Children' => 0
                        ),
                        itemID# => array (
                            'ItemText' => 'Home Sub 2',
                            'ItemLink' => 'somepage2.php',
                            'Children' => 0
                        ),
                    )
            ),
        itemID# => 
            array(
                'ItemText' => 'Contact',
                'ItemLink' => 'contact.php',
                'Children' => 0
            )
        )
    );

Would greatly appreciate if someone could point me in the right direction to accomplish this.如果有人能指出我正确的方向来实现这一点,我将不胜感激。 Thanks!谢谢!

Not too hard.不是太难。 What you do is store the menu items in an array where you can look them up by ID.您所做的是将菜单项存储在一个数组中,您可以在其中通过 ID 查找它们。 Then you iterate over the menu items and if they have a non-null ParentID you add them to their parent's list of children.然后遍历菜单项,如果它们的 ParentID 非空,则将它们添加到其父级的子项列表中。 Then you remove all the children from the master list so you have only top-level items left.然后从主列表中删除所有子项,这样就只剩下顶级项了。

Code:代码:

<?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);
?>

Output:输出:

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
                (
                )

        )

)

Have a function that calls itself every time it gets an array element.有一个每次获取数组元素时都会调用自身的函数。 As in:如:

Your function is called to display a node.调用您的函数以显示节点。 Then it checks if the node its calling from has a sub menu, and if does, it calls itself again.然后它检查它调用的节点是否有子菜单,如果有,它再次调用自己。 And the process repeats until it dies out, and all the previous function calls return.并且这个过程一直重复,直到它消失,并且所有之前的函数调用都返回。

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;
}

Multi-dimensional tree and an unordered HTML list generator多维树和无序 HTML 列表生成器

  1. Recursively build a tree from a multi-dimensional array.从多维数组递归构建
  2. Generate a multi-dimensional HTML list code, from the tree (1).(1)生成多维HTML列表代码。

You can't never know how many dimensions is in the given list of items.您永远无法知道给定的项目列表中有多少维度。 Each element can have a son->Grandson->Great grandson an so on.每个元素可以有一个儿子->孙子->曾孙等等。

So, you must use a recursive function to generate a multi-dimensional list.因此,您必须使用 递归函数来生成多维列表。

Here is the code:这是代码:

<?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 ;
    }
}
?>

The result:结果:

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()
                                        )
                                )
                        )
                )
        )
)

and:和:

<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>

I know this is a late reply but I found this script above and it was fantastic.我知道这是一个迟到的回复,但我在上面找到了这个脚本,它太棒了。 I ran into an issue though with it unsetting my children because of the way the ItemID was working, when I ran it with a similarly designed table to the OP.我遇到了一个问题,但由于 ItemID 的工作方式,当我使用与 OP 设计类似的表运行它时,它使我的孩子感到不安。 To get around this, and given the amount of RAM in most web servers should be able to handle this, I've taken John Kugelman's great example and modified it slightly.为了解决这个问题,并且考虑到大多数 Web 服务器中的 RAM 量应该能够处理这个问题,我采用了John Kugelman 的好例子并对其进行了轻微的修改。 Instead of having to apply children to all of the items and then unsetting them after, I create a new array and build it all in one我不必将子项应用于所有项目然后在之后取消设置它们,而是创建一个新数组并将其全部构建

Code:代码:

$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);

Hope this helps someone else because the above certainly helped me希望这对其他人有所帮助,因为以上内容确实对我有帮助

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM