我真的需要一些帮助来调试一个问题。我试图从一个非常不寻常的数组中构建一个嵌套的对象(树(,我从后端获得(不能访问BE,所以我必须使用我得到的(。我已经完成了95%,但我遇到了错误
我知道StackOverFlow中有很多嵌套对象的平面数组,但我要使用的这个数组却大不相同。它没有展平数组的id或典型属性。好的是我已经完成了大部分。
以下是我遇到的问题的一个基本示例:
数据:
let stackTest = {
predicates: [
{
primaryTerm: "test1",
level: 1,
condition: 0,
},
{
primaryTerm: "and",
level: 1,
condition: 2,
},
{
primaryTerm: "test2",
level: 1,
condition: 0,
},
{
primaryTerm: "and",
level: 1,
condition: 2,
},
{
primaryTerm: "test3",
level: 2,
condition: 0,
},
{
primaryTerm: "or",
level: 2,
condition: 1,
},
{
primaryTerm: "test4",
level: 2,
condition: 0,
},
{
primaryTerm: "or",
level: 2,
condition: 1,
},
{
primaryTerm: "test5",
level: 3,
condition: 0,
},
{
primaryTerm: "and",
level: 3,
condition: 2,
},
{
primaryTerm: "test5",
level: 3,
condition: 0,
},
]
所需功能输出:
[
{
id: 1,
children: [
{
id: 2,
children: [],
parentId: 1,
level: 1,
primaryTerm: 'test1',
condition: 0
},
{
id: 3,
children: [],
parentId: 1,
primaryTerm: 'test2',
level: 1,
condition: 0
},
{
id: 4,
children: [
{
primaryTerm: 'test3',
level: 2,
condition: 0,
id: 5,
children: [],
parentId: 4
},
{
id: 6,
children: [],
parentId: 4,
primaryTerm: 'test4',
level: 2,
condition: 0
},
{
id: 8,
children: [
{
primaryTerm: 'test5',
level: 3,
condition: 0,
id: 9,
children: [],
parentId: 8
},
{
id: 10,
children: [],
parentId: 8,
primaryTerm: 'test5',
level: 3,
condition: 0
}
],
parentId: 4,
level: 2,
primaryTerm: 'and',
condition: 2
}
],
parentId: 0,
level: 1,
primaryTerm: 'or',
condition: 1
}
],
parentId: 0,
level: 0,
primaryTerm: 'and',
condition: 2
}
]
期望的树表示:
AND
/ |
Test1 Test2 OR
/ |
Test3 Test4 AND
|
Test5 Test6
实际功能输出:
[
{
id: 1,
children: [
{
id: 2,
children: [],
parentId: 1,
level: 1,
primaryTerm: 'test1',
condition: 0
},
{
id: 3,
children: [],
parentId: 1,
primaryTerm: 'test2',
level: 1,
condition: 0
},
{
id: 4,
children: [
{
primaryTerm: 'test3',
level: 2,
condition: 0,
id: 5,
children: [],
parentId: 4
},
{
id: 6,
children: [],
parentId: 4,
primaryTerm: 'test4',
level: 2,
condition: 0
},
{
id: 7,
children: [
{
id: 8,
children: [
{
primaryTerm: 'test5',
level: 3,
condition: 0,
id: 9,
children: [],
parentId: 8
},
{
id: 10,
children: [],
parentId: 8,
primaryTerm: 'test5',
level: 3,
condition: 0
}
],
parentId: 7,
level: 2,
primaryTerm: 'and',
condition: 2
}
],
parentId: 1,
level: 1
}
],
parentId: 0,
level: 1,
primaryTerm: 'or',
condition: 1
}
],
parentId: 0,
level: 0,
primaryTerm: 'and',
condition: 2
}
]
实际树表示:
AND
/ |
Test1 Test2 OR
/ |
Test3 Test4 {} --here is the issue
AND
|
Test5 Test6
问题:正在创建一个额外的空对象,该对象根本不应该存在。不确定为什么要创建这个额外的节点。我怀疑这可能与buildEmptyFlatArr有关,它可能没有正确地附加parentId,因为它也被搞砸了。只有当嵌套分支位于树的右侧时才会出现此问题,如果嵌套分支位于该树的左侧,则不会出现此问题。
到目前为止我所做的:
规则:具有"one_answers"/"或"的对象被视为逻辑运算符只有逻辑(AND/OR(对象才能有子对象步骤
- 1:将嵌套的obj(树(初始化到第一个谓词:
buildEmptyFlatArr和listToTree函数处理这个
- 2:当我们到达(And/OR(对象时,将逻辑容器的属性赋予新节点,其中该空节点的级别匹配(logicalObject级别-1(
updatedTreeNode函数处理这个
- 3:如果数组中的以下项与上一个逻辑对象具有相同级别,则将以下对象附加到逻辑对象来自步骤#2的操作员。如果级别不同,请附加一个空节点,直到达到当前循环对象的级别
updatedTreeNode函数处理这个
代码:
let id = 1;
let lastLogical = {};
let lastItemAdded = {};
let initTree;
const buildEmptyFlatArr = (num, branch = false, branchLastValue) =>{
let initArr = [];
for (let i = 0; i {
let map = {},
node,
roots = [],
i;
for (i = 0; i {
tree.forEach((item, index) =>{
if (logical) {
if (item.level === target.level - 1
) {
let objToMod = item;
if (item.condition === undefined) {
for (const [key, value] of Object.entries(target)) {
if (key === "level") {
objToMod["level"] = target.level - 1;
} else {
objToMod[key] = value;
}
}
}
lastLogical = item;
lastItemAdded = item;
} else if (item.children.length >0 ) {
lastLogical = item;
updateTreeNode(item.children, target, first, logical);
}
} else if (first) {
if (item.level === target.level) {
let objToMod = item;
for (const [key, value] of Object.entries(target)) {
objToMod[key] = value;
}
lastItemAdded = item;
return;
} else if (item.children !== null && item.children.length >0) {
updateTreeNode(item.children, target, first, logical);
}
} else if (!first && !logical) {
if (Math.abs(lastLogical.level - target.level) >1) {
let buildArrayLength = target.level - 1;
let arrToAppend = buildEmptyFlatArr(buildArrayLength, true, target);
let newBranchToAppend = listToTree(arrToAppend);
lastLogical.children = [...lastLogical.children, { ...newBranchToAppend[0] }];
lastItemAdded = item;
lastLogical = item;
} else if (item.level === target.level - 1 && lastLogical === item) {
let objToMod = item;
objToMod.children = [
...objToMod.children,
{ id: id, children: [], parentId: item.id, ...target },
];
id += 1;
lastItemAdded = item;
lastLogical = item
} else {
updateTreeNode(item.children, target);
}
}
});
};
const buildTree = (templateData) =>{
templateData.forEach((item, index) =>{
if (index === 0) {
let list = buildEmptyFlatArr(item.level);
initTree = listToTree(list);
updateTreeNode(initTree, item, true, false);
} else if (item.condition === 1 || item.condition === 2) {
updateTreeNode(initTree, item, false, true);
} else {
updateTreeNode(initTree, item);
}
});
};
buildTree(templateObj8.predicates);
console.dir(initTree, { depth: null });
EDIT:我没有很好地提出这个问题(我认为是第一个问题(,作为树的外观的附加示例。我给出的第一个例子是一棵向右加权的树。但是树应该能够处理像这样更复杂的树
第二组数据
let stackTest = {
predicates: [
{
primaryTerm: "test1",
level: 3,
condition: 0,
},
{
primaryTerm: "and",
level: 3,
condition: 2,
},
{
primaryTerm: "test2",
level: 3,
condition: 0,
},
{
primaryTerm: "and",
level: 1,
condition: 2,
},
{
primaryTerm: "test3",
level: 2,
condition: 0,
},
{
primaryTerm: "or",
level: 2,
condition: 1,
},
{
primaryTerm: "test4",
level: 2,
condition: 0,
},
{
primaryTerm: "or",
level: 2,
condition: 1,
},
{
primaryTerm: "test5",
level: 3,
condition: 0,
},
{
primaryTerm: "and",
level: 3,
condition: 2,
},
{
primaryTerm: "test5",
level: 3,
condition: 0,
},
{
primaryTerm: "and",
level: 1,
condition: 2,
},
{
primaryTerm: "test6",
level: 2,
condition: 0,
},
{
primaryTerm: "or",
level: 2,
condition: 1,
},
{
primaryTerm: "test7",
level: 2,
condition: 0,
},
]
我的代码的当前输出
[
{
id: 1,
children: [
{
id: 2,
children: [
{
id: 3,
children: [
{
id: 4,
children: [],
parentId: 3,
level: 3,
primaryTerm: 'test1',
condition: 0
},
{
id: 5,
children: [],
parentId: 3,
primaryTerm: 'test2',
level: 3,
condition: 0
}
],
parentId: 2,
level: 2,
primaryTerm: 'and',
condition: 2
}
],
parentId: 1,
level: 1,
primaryTerm: 'or',
condition: 1
},
{
id: 6,
children: [
{
primaryTerm: 'test3',
level: 2,
condition: 0,
id: 7,
children: [],
parentId: 6
},
{
id: 8,
children: [],
parentId: 6,
primaryTerm: 'test4',
level: 2,
condition: 0
},
{
id: 9,
children: [
{
id: 10,
children: [
{
primaryTerm: 'test5',
level: 3,
condition: 0,
id: 11,
children: [],
parentId: 10
},
{
id: 12,
children: [],
parentId: 10,
primaryTerm: 'test5',
level: 3,
condition: 0
}
],
parentId: 9,
level: 2,
primaryTerm: 'and',
condition: 2
}
],
parentId: 1,
level: 1
}
],
parentId: 0,
level: 1,
primaryTerm: 'or',
condition: 1
},
{
id: 13,
children: [
{
primaryTerm: 'test6',
level: 2,
condition: 0,
id: 14,
children: [],
parentId: 13
},
{
id: 15,
children: [],
parentId: 13,
primaryTerm: 'test7',
level: 2,
condition: 0
}
],
parentId: 0,
level: 1,
primaryTerm: 'or',
condition: 1
}
],
parentId: 0,
level: 0,
primaryTerm: 'and',
condition: 2
}
]
这是我的函数的当前输出,test6和test7已正确插入。空对象所在的位置是插入额外节点的位置。如果这个多余的空物体不在那里,它将是完美的
AND
/ |
OR OR OR
/ / | |
AND test3 test4 {} test6 test7
/ |
test1 test2 and
/
test5 test5
正如您所看到的,id为#9的对象是一个不应该存在的额外对象,这就是正在处理的问题。谢谢
这是一种为每个级别的运算符提供数组的方法。
该树始终包含以运算符为根、以操作数为叶的子树。任何操作数也可以包含子树。
如果某个级别比以前的级别更深,则会创建一个新的子树,其中操作数位于顶部,操作数的子级位于顶部。
const
getTree = predicates => {
const
result = [],
levels = [{ children: result }];
let id = 1,
lastLevel = -Infinity;
predicates.forEach(o => {
const level = o.level;
if (level > lastLevel) {
let l = level - 1;
while (!levels[l]) l--;
while (l < level) {
// generate new operator
// assign children to levels
levels[l].children.push(levels[l + 1] = { id, parentId: levels[l]?.id || 0, children: [] });
id++;
l++;
}
}
if (o.condition) { // update operators
if (!levels[level].condition) Object.assign(levels[level], o);
} else { // assign levels
levels[level].children.push({ id, parentId: levels[level].id, ...o, children: [] });
id++;
}
lastLevel = level;
});
return result;
},
predicates1 = [{ primaryTerm: "test1", level: 1, condition: 0 }, { primaryTerm: "and", level: 1, condition: 2, }, { primaryTerm: "test2", level: 1, condition: 0 }, { primaryTerm: "and", level: 1, condition: 2 }, { primaryTerm: "test3", level: 2, condition: 0 }, { primaryTerm: "or", level: 2, condition: 1 }, { primaryTerm: "test4", level: 2, condition: 0 }, { primaryTerm: "or", level: 2, condition: 1 }, { primaryTerm: "test5", level: 3, condition: 0 }, { primaryTerm: "and", level: 3, condition: 2 }, { primaryTerm: "test5", level: 3, condition: 0 }],
predicates2 = [{ primaryTerm: "test1", level: 3, condition: 0 }, { primaryTerm: "and", level: 3, condition: 2 }, { primaryTerm: "test2", level: 3, condition: 0 }, { primaryTerm: "and", level: 1, condition: 2 }, { primaryTerm: "test3", level: 2, condition: 0 }, { primaryTerm: "or", level: 2, condition: 1 }, { primaryTerm: "test4", level: 2, condition: 0 }, { primaryTerm: "or", level: 2, condition: 1 }, { primaryTerm: "test5",level: 3, condition: 0 }, { primaryTerm: "and",level: 3, condition: 2 }, { primaryTerm: "test5", level: 3, condition: 0 }, { primaryTerm: "and", level: 1, condition: 2 }, { primaryTerm: "test6", level: 2, condition: 0 }, { primaryTerm: "or", level: 2, condition: 1 }, { primaryTerm: "test7", level: 2, condition: 0 }];
console.log(getTree(predicates1));
console.log(getTree(predicates2));
.as-console-wrapper { max-height: 100% !important; top: 0; }
这应该会让你开始:
function parse(tokens, level) {
let expr = []
while (tokens.length) {
let tok = tokens[0]
if (tok.level < level) {
break;
}
if (tok.level === level) {
expr.push(tok.primaryTerm);
tokens.shift();
continue;
}
expr.push(parse(tokens, tok.level))
}
return {op: expr[1], args: expr.filter((_, n) => n % 2 === 0)}
}
对于您的输入,parse(stackTest.predicates, 1)
返回此AST:
{
"op": "and",
"args": [
"test1",
"test2",
{
"op": "or",
"args": [
"test3",
"test4",
{
"op": "and",
"args": [
"test5",
"test5"
]
}
]
}
]
}