【发布时间】:2019-07-30 07:39:54
【问题描述】:
我有一个名为mappings 的表,其中包含id、leaf、parent_id、name 和flip_parent 列。 parent_id 和 flip_parent 都是引用 mapping.id 列的整数。 flip_parent 拥有一个应该从树中排除的值的 id。为此,我有以下函数($mappings 是 mappings 表中的所有行,flipParentIds 是同一表中的所有值,其中 flip_parent 值不是 null)
private function removeFlipParents(array $mappings, array $flipParentIds)
{
foreach ($mappings as $key => $mapping) {
foreach ($flipParentIds as $id) {
if ($mapping['id'] === $id['flipParent']) {
unset($mappings[$key]);
}
}
}
return $mappings;
}
删除这些值后,我需要用剩余的数据构建一棵树(树的深度为 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;
}
在这种情况下,elements 与$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 函数,称为 after removeFlipParents 和 buildTree(这需要完成,因为我需要树结构来检查分支是否有不是的孩子);
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;
}
这有点像我想要它做的,因为它删除了所有不是叶子的无子根节点,但它不会进入第二级及更高级别。它还改变了$nodes 的结构。如果没有 removeChildlessBranches 调用,JSON 将被包装在一个数组 ([{"id": 1, "name": "Node 1", ...}]) 中,我可以在 parseNodes 函数中对其进行迭代,但如果我确实使用 removeChildlessBranches 调用,$nodes 将不再被包装在一个数组 ({"id": 1, "name": "Node 1", ...}) 并且不能被迭代。
所以我的两个问题是,我怎样才能使removeChildlessBranches 真正递归,我怎样才能使它不改变$nodes 的结构?
【问题讨论】:
标签: javascript php symfony recursion tree