【问题标题】:Converting an array from one to multi-dimensional based on parent ID values根据父 ID 值将数组从一维转换为多维
【发布时间】:2011-12-07 18:03:29
【问题描述】:

我有一个代表多维数据的一维对象数组:

array(
    array(
        "id" => 45,
        "parent_id" => null
    ),
    array(
        "id" => 200,
        "parent_id" => 45
    ),
    array(
        "id" => 345,
        "parent_id" => 45
    ),
    array(
        "id" => "355",
        "parent_id" => 200
    )
);

应该如何转换成多维数组:

array(
    array(
        "id" => 45,
        "parent_id" => null,
        "children" => array(
            array(
                "id" => 200,
                "parent_id" => 45,
                "children" => array(
                    "id" => "355",
                    "parent_id" => 200
                )

            ),
            array(
                "id" => 345,
                "parent_id" => 45
            ),
        )
    ),
);

【问题讨论】:

  • 数据是有序的,所以孩子总是在父母之后?
  • @Blem,不是。这是一个很好的问题,顺便说一句。

标签: php arrays recursion multidimensional-array


【解决方案1】:
function convertArray ($array) {
  // First, convert the array so that the keys match the ids
  $reKeyed = array();
  foreach ($array as $item) {
    $reKeyed[(int) $item['id']] = $item;
  }
  // Next, use references to associate children with parents
  foreach ($reKeyed as $id => $item) {
    if (isset($item['parent_id'], $reKeyed[(int) $item['parent_id']])) {
      $reKeyed[(int) $item['parent_id']]['children'][] =& $reKeyed[$id];
    }
  }
  // Finally, go through and remove children from the outer level
  foreach ($reKeyed as $id => $item) {
    if (isset($item['parent_id'])) {
      unset($reKeyed[$id]);
    }
  }
  return $reKeyed;
}

我确信这可以减少到只有两个循环(结合第二个和第三个)但现在我无法为我的生活弄清楚如何......

注意此函数依赖于 parent_id 用于没有父项的项目 NULL 或根本没有设置,因此 isset() 在最后一个循环中返回 FALSE

【讨论】:

  • 第三个循环取消设置所有项目:?
  • 它仅取消设置未设置parent_id 或设置为NULL 的项目(因此isset() 返回FALSE)。如果您的实际数据不是这种情况,您将需要在最后一个循环中修改if,以便它使用没有父项的唯一条件。如果我在提供的示例数据上运行它,它会产生您期望的结果。
  • 谢谢戴夫!这正是问题所在。我照顾它,现在它似乎工作正常。再次感谢!
【解决方案2】:

以下代码示例数组$array 转换为您要查找的树结构:

// key the array by id
$keyed = array();
foreach($array as &$value)
{
    $keyed[$value['id']] = &$value;
}
unset($value);
$array = $keyed;
unset($keyed);

// tree it
$tree = array();
foreach($array as &$value)
{
    if ($parent = $value['parent_id'])
        $array[$parent]['children'][] = &$value;
    else
        $tree[] = &$value;
}
unset($value);
$array = $tree;
unset($tree);

var_dump($array); # your result

这不起作用,如果有一个 现有 父 ID 是 0。但可以轻松更改以反映这一点。

这是一个相关问题,原始数组已被键入,因此解决方案的前半部分可以省略:Nested array. Third level is disappearing

编辑:

那么这是如何工作的呢?这是利用 PHP 变量别名(也称为 references)和(临时)数组,用于存储 a)节点的别名($keyed)和 b)构建新的树顺序($tree )。

您能[...]解释一下$array = $keyed$array = $tree 和未设置的用途吗?

由于$keyed$tree 都包含对$array 中值的引用,我首先将该信息复制到$array 中,例如:

$array = $keyed;

现在$keyed 仍然设置(并且包含对与$array 中相同的值的引用),$keyed 未设置:

unset($keyed);

这将取消设置$keyed 中的所有引用,并确保不再引用$array 中的所有值(值的引用计数减一)。

如果临时数组在迭代后没有取消设置,它们的引用仍然存在。如果您在$array 上使用var_dump,您会看到所有值前面都有一个&,因为它们仍然被引用。 unset($keyed) 删除这些引用,var_dump($array) 再次删除,您将看到 &s 消失了。

我希望这是可以理解的,如果您不流利使用参考资料,有时可能难以理解。它通常有助于我将它们视为变量别名。

如果您想进行一些锻炼,请考虑以下事项:

如何通过一次 foreach 迭代将您的 $array 从平面转换为树?

您自己决定何时单击包含Solution 的链接。

【讨论】:

  • 太棒了!您能否添加 cmets 来解释 $array = $keyed$array = $tree 和 unsets 的用途?
  • @Emanuil Rusev:我添加了关于 assignments 和 unsets 的内容的部分。如果你愿意,可以做一点运动。让我知道;练习的解决方案实际上也是您问题的有效答案,因此可以将其添加到答案中以供以后参考。
  • @EmanuilRusev:在另一个问题PHP variables: references or copies,我也更详细地回答了有关数组和引用的问题。可能对您来说很有趣,所以我将其作为评论留在这里。
猜你喜欢
  • 1970-01-01
  • 2019-12-05
  • 1970-01-01
  • 1970-01-01
  • 2023-03-26
  • 2019-06-29
相关资源
最近更新 更多