Javascript 从嵌套数组中删除无子元素(叶除外)

Javascript 从嵌套数组中删除无子元素(叶除外),javascript,php,symfony,recursion,tree,Javascript,Php,Symfony,Recursion,Tree,我有一个名为mappings的表,其中包含id、leaf、parent\u id、name和flip\u parent列parent\u id和flip\u parent都是引用mappingid列的整数flip_parent保存应从树中排除的值的id。为此,我使用了以下函数($mappings都是mappings表中的行,fliparentis都是同一个表中的值,其中flipp\u parent值不是null) 删除这些值后,我需要用剩余的数据构建一棵树(树的深度为5/6级),这是用下面的代码

我有一个名为
mappings
的表,其中包含
id
leaf
parent\u id
name
flip\u parent
parent\u id
flip\u parent
都是引用
mapping
id
列的整数
flip_parent
保存应从树中排除的值的id。为此,我使用了以下函数(
$mappings
都是
mappings
表中的行,
fliparentis
都是同一个表中的值,其中
flipp\u parent
值不是
null

删除这些值后,我需要用剩余的数据构建一棵树(树的深度为5/6级),这是用下面的代码完成的

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

    foreach ($elements as $element) {
       if ($element['parentId'] == $parentId) {
            $children = $this->buildTree($elements, $element['id']);
            if ($children) {
                $element['children'] = $children;
            } else {
                $element['children'] = [];
            }
        }
    }

    return $branch;
}
在本例中,
元素
$mappings
是相同的数组,但没有这些翻转父元素。此函数的结果作为JSON响应返回,并由Javascript处理以构建树。返回的JSON的结构与此类似

[{
    "id": 1, "name": "Node 1", "children": [{
      "id": 2, "name": "Node 1.1", "children": [{
        "id": 4, "name": "Node 1.1.1", "leaf": true, "children": [], "gls": [{
          "id": 1000, "name": "GL1", "code": "0100"
        }, {
          "id": 1001, "name": "GL2", "code": "0200"
        }]
      }, {
        "id": 5, "name": "Node 1.1.2", "leaf": true, "children": [], "gls": [{
          "id": 2000, "name": "GL3", "code": "0300"
        }, {
          "id": 2001, "name": "GL4", "code": "0400"
        }]
      }]
    }, {
      "id": 3, "name": "Node 1.2", "children": [{
        "id": 6, "name": "Node 1.2.1", "leaf": true, "children": [], "gls": [{
          "id": 3000, "name": "GL5", "code": "0500"
        }, {
          "id": 3001, "name": "GL6", "code": "0600"
        }]
      }]
    }]
  },
  {
    "id": 7, "name": "Node 2", "children": [{
      "id": 8, "name": "Node 2.1", "children": [{
        "id": 9, "name": "Node 2.1.1", "leaf": true, "children": [], "gls": [{
          "id": 4000, "name": "GL7", "code": "0700"
        }, {
          "id": 4001, "name": "GL8", "code": "0800"
        }]
      }]
    }]
  }
]
为了在JS中构建树,我有以下两个函数

parseNodes(nodes)
{
    const ul = document.createElement('ul');
    ul.style.listStyleType = 'none';
    nodes.forEach((node) => {
        const parsedNode = this.parseNode(node);
        if (parsedNode) {
            ul.appendChild(parsedNode);
        }
    });
    return ul;
}

parseNode(node)
{
    if (node.name && node.name !== '') {
        const li = document.createElement('li');
        li.className = node.leaf ? 'leaf' : 'parent';
        li.setAttribute('data-mapping-id', node.id);

        if (node.parentId) {
            li.setAttribute('data-parent-id', node.parentId);
        }

        li.innerHTML = node.name;

        if (node.children) {
            li.appendChild(this.parseNodes(node.children));
        }

        return li;
    }
    return null;
}
这一切都很好,但我现在想从树中删除无子节点、非叶节点,因为只有叶节点才真正可用。我不知道无子节点处于什么级别,而且并非所有无子节点都处于同一级别

为此,我编写了一个递归PHP函数,在
removeFlipParents
buildTree
之后调用它(这需要完成,因为我需要树结构来检查分支是否有子级)

这有点像我希望它做的,因为它删除了所有不是叶子的无子根节点,但它不会进入第二级或更高级别。它还更改了
$nodes
的结构。没有
removechildlessbranchs
调用,JSON被包装在一个数组中(
[{“id”:1,“name”:“Node 1”,…}
),我可以在
parseNodes
函数中对其进行迭代,但是如果我使用
removechildlessbranchs
调用,
$nodes
不再被包装在一个数组中(
{“id”:1,“name”):“节点1”,…}
),无法对其进行迭代


所以我的两个问题是,我如何使
removechildlessbranchs
真正递归,以及如何使它不改变
$nodes
的结构?

你在这一行传递
$node['children']
数组的副本
$this->removechildlessbranchs($node['children']);
(如果您在查找“按引用传递”和“按值传递”之前没有听说过它)。因此,将对该副本而不是原始数组(也是副本)进行任何后续更改。更改的结果将被丢弃,因为您没有对它们做任何操作

您可以通过将行更改为this
$nodes[$key]['children']=$this->removechildlessbranchs($node['children']);
来解决该问题

但是,请注意,您现在可能有一个没有子节点且不是叶节点的节点,但由于您已经在该级别进行了修剪,因此将无法正确删除该节点。首先修剪子节点,然后取消设置将获得所需的结果:

专用函数removeChildlessBranchs(数组$nodes)
{
foreach($key=>$node的节点){
$nodes[$key]['children']=$this->removeChildlessbranchs($node['children']);
if(空($nodes[$key]['children'])&&&!$nodes[$key]['leaf'])){
取消设置($nodes[$key]);
}
}
返回$nodes;
}

谢谢,这似乎是我想要的方式!不过,还有一件事,该函数仍然返回一个对象对象对象,而我需要它是一个对象数组。我如何强制执行该操作?PHP函数将返回一个数组数组。实际上是json_encode函数给您带来了麻烦。因为您正在取消设置数组值y你现在有“缺失”的数组索引。JavaScript不支持无序数组键,因此json_编码的唯一解决方案是将数组作为对象进行编码。一旦我们知道并理解了原因,我们就可以通过使用来修复数组索引,从而得到所需的结果,因此我们最终得到
json_编码(数组_值($nodes))
实际上,这种方法存在一种边缘情况。
子对象可能仍然被编码为对象,因为它们可能仍然有顺序错误的键。要使事情更干净并解决此问题,请将
RemoveChildlessBranchs
函数的最后一行更改为
返回数组值($nodes)
这样你就可以保证你的数组是有序的。这就是我现在所做的,它工作得非常好,谢谢!
parseNodes(nodes)
{
    const ul = document.createElement('ul');
    ul.style.listStyleType = 'none';
    nodes.forEach((node) => {
        const parsedNode = this.parseNode(node);
        if (parsedNode) {
            ul.appendChild(parsedNode);
        }
    });
    return ul;
}

parseNode(node)
{
    if (node.name && node.name !== '') {
        const li = document.createElement('li');
        li.className = node.leaf ? 'leaf' : 'parent';
        li.setAttribute('data-mapping-id', node.id);

        if (node.parentId) {
            li.setAttribute('data-parent-id', node.parentId);
        }

        li.innerHTML = node.name;

        if (node.children) {
            li.appendChild(this.parseNodes(node.children));
        }

        return li;
    }
    return null;
}
private function removeChildlessBranches(array $nodes)
{
    foreach ($nodes as $key => $node) {
        if (empty($node['children']) && !$node['leaf']) {
            unset($nodes[$key]);
        } else {
            $this->removeChildlessBranches($node['children']);
        }
    }

    return $nodes;
}