根据父ID值将数组从一个转换为多维

时间:2011-10-14 12:59:41

标签: php arrays recursion multidimensional-array

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

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

2 个答案:

答案 0 :(得分:3)

以下代码示例数组$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中的所有值都不再被引用(值的引用计数减1)。

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

我希望这是可以理解的,如果你不能流利地参考,有时可能难以理解。它通常可以帮助我将它们视为可变别名。

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

  

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

如果您想点击包含Solution的链接,请自行决定。

答案 1 :(得分: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在最后一个循环中。