【问题标题】:Sorting array by children?按孩子排序数组?
【发布时间】:2012-08-16 10:48:49
【问题描述】:

我有一个看起来像这样的数组

array(
    1 => array(
        'id'     => 1,
        'name'   => 'first',
        'parent' => null
    ),
    2 => array(
        'id'     => 2,
        'name'   => 'second',
        'parent' => null
    ),
    3 => array(
        'id'     => 3,
        'name'   => 'third',
        'parent' => 1
    ),
    4 => array(
        'id'     => 4,
        'name'   => 'fourth',
        'parent' => 3
    ),
    5 => array(
        'id'     => 5,
        'name'   => 'fifth',
        'parent' => 1
    ),        
);

但我想将任何“子”项移动到数组下的“子”键。 所以,我想结束

array(
    1 => array(
        'id'       => 1,
        'name'     => 'first',
        'parent'   => null,
        'children' => array(
            3 => array(
                'id'       => 3,
                'name'     => 'third',
                'parent'   => 1,
                'children' => array(
                    4 => array(
                        'id'       => 4,
                        'name'     => 'fourth',
                        'parent'   => 3,
                        'children' => array()
                    ),
                )
            ),
            5 => array(
                'id'       => 5,
                'name'     => 'fifth',
                'parent'   => 1,
                'children' => array()
            )
        )
    ),
    2 => array(
        'id'       => 2,
        'name'     => 'second',
        'parent'   => null,
        'children' => array()
    )
);

但老实说,我完全不知道从哪里开始。

我在想也许循环遍历数组中的每个项目,然后在使用 $new_array[$current['parent']]['children'][$current['id']] = $current; 时构建新数组

但我一碰到嵌套项目就会遇到问题。

我可以构建一个函数,该函数采用当前数组和整个数组并递归地向上移动树以找到所有父级并因此找到整个路径,但如果其中一个父级尚未创建,我会再次遇到问题还没有。

我能想到的唯一选择是构建一个包含不同级别父级的数组映射,然后递归地循环遍历它并以这种方式获取所有元素,但这似乎效率不高?

谁能提出解决方案?

【问题讨论】:

  • 我一直在努力解决这个问题...... 一个问题:Elem 4 是否有可能在初始数组中出现在 Elem 3 之后? (我想知道的是是否有可能必须在其父节点之前创建子节点) - 是的,当涉及树时,递归是我想到的第一件事......但是我们必须小心...细节... ;-)(我还没有做对)
  • @Dr.Kameleon 我相信我的解决方案在这种情况下可以满足 OP 的要求。不过,它只适用于 PHP 5 以后的版本,因为据我所知,引用在 4 中并不完全存在。

标签: php arrays recursion multidimensional-array


【解决方案1】:

您对 foreach 循环的想法是正确的。但是,您想要做的事情需要引用的“魔力”。

foreach($oldArray as $key => &$item) {
    if($item["parent"] == null) $newArray[$key] = &$item;
    else $oldArray[$item["parent"]]["children"][$key] = &$item;
}

unset($item);

这将输出'$oldArray'

Array
(
[1] => Array
    (
        [id] => 1
        [name] => first
        [parent] => 
        [children] => Array
            (
                [3] => Array
                    (
                        [id] => 3
                        [name] => third
                        [parent] => 1
                        [children] => Array
                            (
                                [4] => Array
                                    (
                                        [id] => 4
                                        [name] => fourth
                                        [parent] => 3
                                    )

                            )

                    )

                [5] => Array
                    (
                        [id] => 5
                        [name] => fifth
                        [parent] => 1
                    )

            )

    )

[2] => Array
    (
        [id] => 2
        [name] => second
        [parent] => 
    )

[3] => Array
    (
        [id] => 3
        [name] => third
        [parent] => 1
        [children] => Array
            (
                [4] => Array
                    (
                        [id] => 4
                        [name] => fourth
                        [parent] => 3
                    )

            )

    )

[4] => Array
    (
        [id] => 4
        [name] => fourth
        [parent] => 3
    )

[5] => Array
    (
        [id] => 5
        [name] => fifth
        [parent] => 1
    )

)

对于 newArray(“纯化”版本)

Array
(
[1] => Array
    (
        [id] => 1
        [name] => first
        [parent] => 
        [children] => Array
            (
                [3] => Array
                    (
                        [id] => 3
                        [name] => third
                        [parent] => 1
                        [children] => Array
                            (
                                [4] => Array
                                    (
                                        [id] => 4
                                        [name] => fourth
                                        [parent] => 3
                                    )

                            )

                    )

                [5] => Array
                    (
                        [id] => 5
                        [name] => fifth
                        [parent] => 1
                    )

            )

    )

[2] => Array
    (
        [id] => 2
        [name] => second
        [parent] => 
    )

)

现在,为什么会这样: 通过将 &item 放入 foreach 循环,我们使用对项目的引用,而不是副本。这意味着,无论我们对该项目进行什么更改,我们都会在相应的数组元素处进行更改。

通过将 &$item 传递给 $newArray[$key] 或 children 数组,我们将引用传递...所以无论我们对“原始对象”(即 [3])做什么,我们也会这样做所有参考文献。

unset($item) 是必要的,因为它删除了 $item 的最后一个实例和变量之间的绑定。否则,只要我们再次更改 $item 变量,我们也会更改最后一个变量。在这个脚本中不是完全必要的,但仍然是一个值得记住的好习惯。

【讨论】:

  • 但是当您到达多个级别时会遇到问题,例如当您点击4 时,您已经将3 移动到1 的子数组中,因此3 键在您尝试访问它时不再存在,您需要$item[1]['children'][3]['children'][4] 有意义吗?
  • @Hailwood 是的,我知道你的意思,我目前正在制定正确的解决方案。请稍等:)
  • @Hailwood 抱歉耽搁了这么久,这比我最初想象的要复杂一些,但很简单。现在看看,它应该是这样工作的。
  • @ATaylor 太好了,所以我不会在这里写我的 25 行代码。我也走得太远了。该死的,这么简单:D
  • @ATaylor 嗯,这是那些让我们的脑细胞“发痒”并让我们所有人都为被称为程序员而感到自豪的小编码挑战之一。老实说,我玩这个已经有一段时间了,我必须说你的方法可能是我见过的最聪明、最优雅的方法之一。
【解决方案2】:

您可以将它们从数组转换为对象。这很容易做到,你几乎已经有了一个对象结构。

不同之处在于您可以在每个对象中设置一个 __construct() 函数,将其作为参数传递给它的 ID 数字,并在 __construct() 函数中查看子对象的主数组并将它们添加到. 当它添加一个新的子项时,它会再次触发该子项中的__construct() 函数,该函数将再次在数组中搜索它自己的子项。

你很可能会在几乎没有工作的情况下得到一个很棒的对象。如果您希望在最后将它们作为一个数组,您可以有一个函数将整个 heirachy 作为一个数组返回 - 但对象对您来说不是更好吗?

【讨论】:

    猜你喜欢
    • 2021-08-15
    • 1970-01-01
    • 2020-05-04
    • 1970-01-01
    • 1970-01-01
    • 2017-10-15
    • 1970-01-01
    • 2016-01-31
    • 1970-01-01
    相关资源
    最近更新 更多