我有一个带有孩子的数据树结构:
{ id: 1,
name: "Dog",
parent_id: null,
children: [
{
id: 2,
name: "Food",
parent_id: 1,
children: []
},
{
id: 3,
name: "Water",
parent_id: 1,
children: [
{
id: 4,
name: "Bowl",
parent_id: 3,
children: []
},
{
id: 5,
name: "Oxygen",
parent_id: 3,
children: []
},
{
id: 6,
name: "Hydrogen",
parent_id: 3,
children: []
}
]
}
]
}
这表示DOM结构,用户可以通过单击DOM中的相应按钮从中选择要删除的项目。
我有一个选定项目的已知文本标题,该变量将从DOM中删除,并设置为变量clickedTitle。我在寻找一种算法时遇到了麻烦,该算法将允许我从深度嵌套的树中删除正确的对象数据。
这是我的代码:
function askUserForDeleteConfirmation(e) {
const okToDelete = confirm( 'Are you sure you want to delete the item and all of its sub items?' );
if(!okToDelete) {
return;
}
const tree = getTree(); // returns the above data structure
const clickedTitle = getClickedTitle(e); // returns string title of clicked on item from DOM - for example "Dog" or "Bowl"
const updatedTree = removeFromTree(tree, tree, clickedTitle);
return updatedTree;
}
function removeFromTree(curNode, newTree, clickedTitle) {
if(curNode.name === clickedTitle) {
// this correctly finds the matched data item to delete but the next lines don't properly delete it... what to do?
const index = curNode.children.findIndex(child => child.name === clickedTitle);
newTree = curNode.children.slice(index, index + 1);
// TODO - what to do here?
}
for(const node of curNode.children) {
removeFromTree(node, newTree, clickedTitle);
}
return newTree;
}
我尝试使用Removing matched object from array of objects using javascript中的信息,但没有成功。
答案 0 :(得分:2)
如果您不介意修改参数树in-place,则可以完成这项工作。请注意,如果您尝试删除根目录,它将返回null
。
const tree = { id: 1, name: "Dog", parent_id: null, children: [ { id: 2, name: "Food", parent_id: 1, children: [] }, { id: 3, name: "Water", parent_id: 1, children: [ { id: 4, name: "Bowl", parent_id: 3, children: [] }, { id: 5, name: "Oxygen", parent_id: 3, children: [] }, { id: 6, name: "Hydrogen", parent_id: 3, children: [] } ] } ] };
const removeFromTree = (root, nameToDelete, parent, idx) => {
if (root.name === nameToDelete) {
if (parent) {
parent.children.splice(idx, 1);
}
else return null;
}
for (const [i, e] of root.children.entries()) {
removeFromTree(e, nameToDelete, root, i);
}
return tree;
};
console.log(removeFromTree(tree, "Oxygen"));
您当前的代码非常正确。但是:
newTree = curNode.children.slice(index, index + 1);
突出了一些问题:我们需要操纵父级的children
数组来删除curNode
而不是curNode
自己的children
数组。我通过调用递归传递父对象和子索引,从而省去了线性操作findIndex
的麻烦。
此外,从index
到index + 1
的切片仅提取一个元素,而不会修改curNode.children
。使用newArray
或通过调用堆栈返回它的方法尚不清楚。 splice
似乎更适合执行当前任务:就地提取一个元素。
请注意,此功能将删除多个与nameToDelete
匹配的条目。
答案 1 :(得分:1)
我建立了如下算法:
function omitNodeWithName(tree, name) {
if (tree.name === name) return undefined;
const children = tree.children.map(child => omitNodeWithName(child, name))
.filter(node => !!node);
return {
...tree,
children
}
}
您可以使用它返回不包含该项目的新树:
noHydrogen = omitNodeWithName(tree, "Hydrogen")
答案 2 :(得分:0)
我喜欢@VictorNascimento的答案,但是通过依次应用map
和filter
,每个children
列表将被迭代两次。这是reduce
的替代选择,可以避免这种情况:
function removeFromTree(node, name) {
return node.name == name
? undefined
: {
...node,
children: node.children.reduce(
(children, child) => children.concat(removeFromTree (child, name) || []), [])
}
}
如果您想要一种如@ggorlen所建议的就地删除项目的方法,我建议采用以下解决方案,我认为这更简单:
function removeFromTree(node, name) {
if (node.name == name) {
node = undefined
} else {
node.children.forEach((child, id) => {
if (!removeFromTree(child, name)) node.children.splice(id, 1)
})
}
return node
}
答案 3 :(得分:0)
我们使用object-scan来进行所有这样的数据处理。一旦将头缠住它,它就会非常强大。这是您回答问题的方式
const objectScan = require('object-scan');
const prune = (name, input) => objectScan(['**[*]'], {
rtn: 'bool',
abort: true,
filterFn: ({ value, parent, property }) => {
if (value.name === name) {
parent.splice(property, 1);
return true;
}
return false;
}
})(input);
const obj = {"id":1,"name":"Dog","parent_id":null,"children":[{"id":2,"name":"Food","parent_id":1,"children":[]},{"id":3,"name":"Water","parent_id":1,"children":[{"id":4,"name":"Bowl","parent_id":3,"children":[]},{"id":5,"name":"Oxygen","parent_id":3,"children":[]},{"id":6,"name":"Hydrogen","parent_id":3,"children":[]}]}]};
console.log(prune('Oxygen', obj)); // return true iff pruned
// => true
console.log(JSON.stringify(obj));
// => {"id":1,"name":"Dog","parent_id":null,"children":[{"id":2,"name":"Food","parent_id":1,"children":[]},{"id":3,"name":"Water","parent_id":1,"children":[{"id":4,"name":"Bowl","parent_id":3,"children":[]},{"id":6,"name":"Hydrogen","parent_id":3,"children":[]}]}]}