【问题标题】:Create a tree from a flat array从平面数组创建树
【发布时间】:2021-02-12 16:36:13
【问题描述】:

我在转换平面数组时遇到问题,例如从数据库查询到树结构。 我有这样的事情:

[
  [ 
    id => 11,
    path => '/11',
    label => 'AAA'
  ],
  [ 
    id => 12,
    path => '/12',
    label => 'BBB'
  ],
  [ 
    id => 21,
    path => '/12/21',
    label => 'BBBB'
  ],
  [ 
    id => 21,
    path => '/12/22',
    label => 'CCCCC'
  ],
]

path 指向树内的层次位置,由 id 定义。所以最后我必须得到这样的东西:

$tree=[
        [
            'id' => '11',
            'label' =>  'AAA'
        ],
        [
            'id' => '12',
            'label' =>  'BBB',
            'children' => [
                [
                    'id' => '21',
                    'label' =>  'BBBB'
                ],
                [
                    'id' => '22',
                    'label' =>  'CCCCC'
                ]
            ]
        ]
    ];

深度可以是无限的。我将不胜感激任何解决方案。谢谢你:-)

【问题讨论】:

  • 对不起,你为什么要做这种可怕的事情?
  • 假设这是可能的。当你访问一个id为'/x/y'的节点时,你可以保证你已经访问过id为'/x'的节点?
  • 您能否发布您已经拥有的代码以及它失败的地方?
  • @AndréWalker 开始的结构来自 Moodle insatnce,它以这种方式组织其类别。提供分层选择菜单的 Vue 组件需要目标结构。所以,我别无选择。
  • @AndréWalker 一开始你有一个扁平的结构,你可以用任何方式对它进行排序,例如你可以按路径的深度对条目进行排序。这样你就可以保证你已经访问过'x'了。

标签: php algorithm tree


【解决方案1】:

谢谢大家,但我仍然卡住了 :-( 到目前为止,这是我的方式。

首先,我按深度排序类别并按此顺序循环它们。这样我就可以确定父节点存在了。

    public function buildCategoryTree() {
        // order by depth
        $categoryLevel = [];
        foreach (Category::all() as $category) {
            $catPathSplitted = array_filter(explode("/", $category->path));
            $categoryLevel[count($catPathSplitted)][] = $category;
        }

        $categoryTree = [];

        // now loop each level and create a tree node
        foreach ($categoryLevel as $level => $categories) {
            foreach ($categories as $category) {
                $test = $category->path;
                $catPathSplitted = array_filter(explode("/", $category->path));
                $categoryTree = $this->addNode($category, $catPathSplitted, $categoryTree, $test);
            }
        }        
    } 

然后我尝试使用这种递归,但它只能部分起作用,这意味着我按层次顺序获取子节点, 但是子节点也会在每个级别上再次创建。所以有问题:-(

    private function addNode($cat, $keys, &$tree) {
        foreach ($keys as $counter => $id) {
            if (!next($keys)) {
                if (!isset($tree[$id]['category'])) {
                    $tree[$id]['category'] = $cat->toArray();
                }
            } else {
                if (!isset($tree[$id]['children'])) {
                    $tree[$id]['children'] = [];
                }
                array_shift($keys);
                $this->addNode($cat, $keys, $tree[$id]['children'], $test);

            }
        }
        return $tree;
    }

任何人都可以发现缺陷吗?

【讨论】:

  • 知道了 :-) 根本不需要递归。谢谢你的提示。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-09-25
  • 1970-01-01
  • 2021-08-21
  • 2019-10-12
  • 2020-08-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多