在PHP中使用parentIds创建多级数组

时间:2010-02-16 14:12:12

标签: php arrays

我正在尝试设置一个可以有多个级别的列表,使用parentId来定义其父级。第一项parentId为NULL。一些条目的例子:

id parentId name
1    NULL     item1
2    NULL     item2
3    1        item3
4    2        item4
5    3        item5
6    3        item6

所以,1和2是主要项目; 3是1的孩子; 4是2的孩子; 5是3的孩子(1本身的孩子); 6也是3的孩子(自己是1的孩子);等

我无法创建一个正确添加这些项目到正确级别的数组。它应该是这样的:


Array
(
    [1] => Array
        (
            [name] => item1
            [parentId] => 
            [children] => Array
                (
                    [3] => Array
                        (
                            [name] => item3
                            [parentId] => 1
                            [children] => Array
                                (
                                    [5] => Array
                                        (
                                            [name] => item5
                                            [parentId] => 3
                                        )

                                    [6] => Array
                                        (
                                            [name] => item6
                                            [parentId] => 3
                                        )

                                )

                        )

                )

        )

    [2] => Array
        (
            [name] => item2
            [parentId] => 
            [children] => Array
                (
                    [4] => Array
                        (
                            [name] => item4
                            [parentId] => 2
                        )

                )

        )

)

但是说我使用foreach()查看了所有项目,然后我转到第5项。它的parentId是3,但是在那时,我不知道这个父3在数组中的位置,并且如何将孩子添加到该父母。

是否有一个技巧可以循环使用这些项目,并以正确的方式将它们全部放在适当位置?

4 个答案:

答案 0 :(得分:11)

这是

// your original data as an array
$data = array(
    array(
        'id' => 1,
        'parentId' => null,
        'name' => 'item1'
    ),
    array(
        'id' => 2,
        'parentId' => null,
        'name' => 'item2'
    ),
    array(
        'id' => 3,
        'parentId' => 1,
        'name' => 'item3'
    ),
    array(
        'id' => 4,
        'parentId' => 2,
        'name' => 'item4'
    ),
    array(
        'id' => 5,
        'parentId' => 3,
        'name' => 'item5'
    ),
    array(
        'id' => 6,
        'parentId' => 3,
        'name' => 'item6'
    ),
);

递归函数

function buildTree( $ar, $pid = null ) {
    $op = array();
    foreach( $ar as $item ) {
        if( $item['parentId'] == $pid ) {
            $op[$item['id']] = array(
                'name' => $item['name'],
                'parentId' => $item['parentId']
            );
            // using recursion
            $children =  buildTree( $ar, $item['id'] );
            if( $children ) {
                $op[$item['id']]['children'] = $children;
            }
        }
    }
    return $op;
}

print_r( buildTree( $data ) );

/*
Array
(
    [1] => Array
        (
            [name] => item1
            [parentId] => 
            [children] => Array
                (
                    [3] => Array
                        (
                            [name] => item3
                            [parentId] => 1
                            [children] => Array
                                (
                                    [5] => Array
                                        (
                                            [name] => item5
                                            [parentId] => 3
                                        )

                                    [6] => Array
                                        (
                                            [name] => item6
                                            [parentId] => 3
                                        )

                                )

                        )

                )

        )

    [2] => Array
        (
            [name] => item2
            [parentId] => 
            [children] => Array
                (
                    [4] => Array
                        (
                            [name] => item4
                            [parentId] => 2
                        )

                )

        )

)
*/

答案 1 :(得分:1)

您应该使用项目的ID作为数组的键值,以便您可以通过以下方式向其父项添加项目:

$array[$parentID]['children'][$childID] = array();

答案 2 :(得分:1)

首先想到的只是你所拥有的平面版本:

array (
[0] => array(
    'name' => 'item1',
    'parent' => null
    ),
[1] => array(
    'name' => 'item2',
    'parent' => null
    ),
[3] => array(
    'name' => 'item3',
    'parent' => 0
    ),
[4] => array(
    'name' => 'item4',
    'parent' => 3
    ),
[5] => array(
    'name' => 'item5',
    'parent' => 1
    ),
[6] => array(
    'name' => 'item6',
    'parent' => 1
    ), );

基本上,您只能引用回父母。要找到所有孩子,你必须遍历数组。不过,初始设置时间会非常快。

第二个想到的,会涉及更多的设置,但后来访问时间会少得多:

array (
[0] => array(
    'name' => 'item1',
    'parent' => null,
    'children' = array(3)
    ),
[1] => array(
    'name' => 'item2',
    'parent' => null
    'children' = array(5, 6)
    ),
[3] => array(
    'name' => 'item3',
    'parent' => 0
    'children' = array(4)
    ),
[4] => array(
    'name' => 'item4',
    'parent' => 3
    'children' = array()
    ),
[5] => array(
    'name' => 'item5',
    'parent' => 1
    'children' = array()
    ),
[6] => array(
    'name' => 'item6',
    'parent' => 1
    'children' = array()
    ), );

在这一个中,您将所有子索引添加到父级。这需要更长的时间,但随后的访问时间会很快。当你弄清楚父母的时候,你只需要附加到父母的子阵列上。

第二种方法唯一真正的缺点是,如果要添加或删除项目,则必须记住返回并更新父项的子数组。

答案 3 :(得分:0)

您可能不再需要新的解决方案,但这对其他用户来说可能会派上用场:

// ! assuming $elements is built like: Array( id1 => Array(/*parameters*/) , ...)

function buildTree($elements) {

    $e = Array(0 => Array()); // elements array
    $r = Array(0 =>& Array()); // reference array

    while ($elements) {// repeat till $elements is empty

        // loop through (remaining) elements
        foreach ($elements as $id => $element) {

            $pid = $element['parentId']; // shortcut

            if (array_key_exists($pid,$r)) { // parent already parsed -> can add this element

                // use parent's reference to elements array to add this element ( $r[$pid] =& $e[path][to][$pid] )
                $r[$pid] ['elements'][$id] = $element;

                // create reference for this element using parent's reference
                $r[$id] =& $r[$pid]['elements'][$id];

                // unset current element in input array in order to limit while-loop
                unset($elements[$id]);

            }

        }
    }

return $e; // or whatever you need, the reference array can be useful if you need to fetch an element only knowing its id

}

它的作用:

  • 为结果声明一个数组($e)并添加根元素(0/null
  • 为引用($r)声明一个数组,并已将$r[0]引用到$e[0]
  • 循环输入数组,直到它为空
    • 为每个元素做:
    • 检查父母是否已被处理,如果是,你知道这个元素属于哪里并且可以添加它 (这是阻止我在前几次尝试中使用它以及为什么需要while循环)的原因。
    • 使用父参考添加当前元素(请注意&之后的=!)
    • 使用父级参考
    • 创建新参考
    • 取消设置输入数组中的当前元素 (如果你喜欢无限的while循环,你可以留下这个;))
  • of cource return你需要什么!

这种方法的好处是:

  • 你减少了foreach循环的数量(你可以根据目前的知识分配最多)
  • 每个循环变短,因为您取消设置输入数组中的已解析元素($elements
  • 你也可以返回参考数组,并且能够快速获取元素的参数,假设你知道它的id

换句话说:它应该更快(我没有测试过它!),至少对于我使用它的更复杂的任务来说。