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


adding one more level to a hierarchical multi-dimensional array

>更新:

这是一个从 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
                                  )
                              )
                           )
                      )

            )
    )

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 )。因此,将来可能添加到原始平面数组中的任何键都将传递到新的转换数组树中,而无需修改代码。

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

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