为分层多维数组添加一个级别

时间:2015-01-18 20:51:19

标签: php arrays tree hierarchical-data

更新

这是从mysql获取的平面数组。我使用闭包表来存储层次关系:

Array
(
    [0] => Array
        (
            [brand] => Intel
            [id] => 53
            [name] => CPU 1978
            [parent_id] => 0
        )

    [1] => Array
        (
             [brand] => Asus
             [id] => 537
             [name] => CPU 1999
             [parent_id] => 53
        )

    [2] => Array
        (
             [brand] => HTC
             [id] => 538
             [name] => CPU 1998
             [parent_id] => 53
        )
)

我有一些数据显示新产品所基于的古代产品。我正在使用以下代码将平面数组转换为分层的多维数组:

function buildTree(array $elements, $parentId = 0) {
 $branch = array();

 foreach ($elements as $element) {
    if ($element['parent_id'] == $parentId) {
        $children = buildTree($elements, $element['id']);
        if ($children) {
            $element['children'] = $children;
        }
        $branch[] = $element;
    }
 }

 return $branch;
}

结果:

Array
(
    [0] => Array
        (
            [brand] => Intel
            [id] => 53
            [name] => CPU 1978
            [parent_id] => 0
            [children] => Array
                (
                    [0] => Array
                        (
                            [brand] => Asus
                            [id] => 537
                            [name] => CPU 1999
                            [parent_id] => 53
                        )

                    [1] => Array
                        (
                            [brand] => HTC
                            [id] => 538
                            [name] => CPU 1998
                            [parent_id] => 53
                        )

                )

        )

)

我想通过向第一级添加新密钥brands来重新组织树,并将子项的品牌提取为二级数组键,如下所示:

Array
(
    [0] => Array
        (
            [brand] => Intel
            [id] => 53
            [name] => CPU 1978
            [parent_id] => 0
            [brands]=> Array
                    (
                      [Asus]=> Array
                           (
                             [0] => Array
                             (
                               [id] => 537
                               [name] => CPU 1999
                               [parent_id] => 53
                             )
                           )

                      [HTC] => Array
                          (
                            [0]=>Array
                              (
                                [id] => 538
                                [name] => CPU 1998
                                [parent_id] => 53
                              )
                          )
                      [Intel]=>Array() // Keep this one for new CPU from Intel
                    )


        )

)

我尝试再创建一个功能,将品牌插入父级别,但我的问题是,如何将孩子的CPU放入相应的品牌?

function brand(array $elements,$children){
  $branch = array();
  foreach($elements as $k=>$element){          
    /* if($element['brand'] == $children['brand']) not working **/
     $branch[$element['brand']] = $children;
  }
  return $branch;
}

function buildTree(array $elements, $parentId = 0) {
 $branch = array();

 foreach ($elements as $element) {
    if ($element['parent_id'] == $parentId) {
        $children = buildTree($elements, $element['id']);
        if ($children) {
            $element['brands'] = brand($elements,$children);

        }
        $branch[] = $element;
    }
 }

 return $branch;
}

这给了我这个结果:

 Array
    (
        [0] => Array
            (
                [brand] => Intel
                [id] => 53
                [name] => CPU 1978
                [parent_id] => 0
                [brands]=> Array
                        (
                          [Asus]=> Array
                               (
                                 [0] => Array
                                 (
                                   [brand]=> Asus
                                   [id] => 537
                                   [name] => CPU 1999
                                   [parent_id] => 53
                                 )
                                 [1]=>Array
                                  (
                                    [brand]=>HTC
                                    [id] => 538
                                    [name] => CPU 1998
                                    [parent_id] => 53
                                  )
                               )

                          [HTC] => Array
                              (
                                 [0] => Array
                                 (
                                   [brand]=> Asus
                                   [id] => 537
                                   [name] => CPU 1999
                                   [parent_id] => 53
                                 )
                                  [1]=>Array
                                  (
                                    [brand]=>HTC
                                    [id] => 538
                                    [name] => CPU 1998
                                    [parent_id] => 53
                                  )
                              )
                          [Intel]=>Array(
                              (
                                 [0] => Array
                                 (
                                   [brand]=> Asus
                                   [id] => 537
                                   [name] => CPU 1999
                                   [parent_id] => 53
                                 )
                                  [1]=>Array
                                  (
                                    [brand]=>HTC
                                    [id] => 538
                                    [name] => CPU 1998
                                    [parent_id] => 53
                                  )
                              )
                           )
                      )


            )

    )

2 个答案:

答案 0 :(得分:2)

编辑:当品牌有多个子元素时,我之前的答案失败了。以下是一个更强大的解决方案。

function buildTree(array $elements, $parentId = 0)
{
    $branch = [];

    foreach ($elements as $element) {
        if ($element['parent_id'] == $parentId) {
            $element['brands'] = brand(buildTree($elements, $element['id']));

            $branch[] = $element;
        }
    }

    return $branch;
}

function brand(array $elements)
{
    $branch = [];
    foreach ($elements as $element) {
        $branch[$element['brand']][] = [
            'id' => $element['id'],
            'name' => $element['name'],
            'parent_id' => $element['parent_id'],
        ];
    }

    return $branch;
}

这将从原始数组中返回以下内容:

Array
(
    [0] => Array
        (
            [brand] => Intel
            [id] => 53
            [name] => CPU 1978
            [parent_id] => 0
            [brands] => Array
                (
                    [Asus] => Array
                        (
                            [0] => Array
                                (
                                    [id] => 537
                                    [name] => CPU 1999
                                    [parent_id] => 53
                                )
                        )
                    [HTC] => Array
                        (
                            [0] => Array
                                (
                                    [id] => 538
                                    [name] => CPU 1998
                                    [parent_id] => 53
                                )
                        )
                )
        )
)

答案 1 :(得分:1)

RedGiant,以下函数将获取现有buildTree()方法的输出,并以一种方式对其进行递归转换,使得数组树中的所有children元素都将替换为brands

function brand(array $elements)
{
    // Return early if parent has no children
    if (! array_key_exists('children', $elements)) {
        return $elements;
    }

    // Initialise local values
    $brands = array();

    // Transform children (recursively)
    foreach ((array) $elements['children'] as $child) {
        $brand = $child['brand'];
        unset($child['brand']);

        // Use call_user_func() and __function__ to prevent name dependency
        // within the function itself. If required, this can be replaced with:
        // $brands[$brand] = array(brand($child);
        $brands[$brand] = array(call_user_func(__function__, $child));
    }

    // Replace children with brands
    unset($elements['children']);
    $elements['brands'] = $brands;

    return $elements;
}

应该通过array_map()调用该函数,即:

$old_tree = buildTree($original_flat_array)
$new_tree = array_map('brand', buildTree($original_flat_array));

此解决方案的优点是它可以保留所有现有的数组键(显然除了children)。因此,您将来可能添加到原始平面数组的任何键都将被传输到新的变换后的数组树中,而无需进行代码修改。