我正在尝试创建一个树组件。但是我不知道如何递归地删除树中的项目。
每个项目都是动态创建的,我想在每个级别中删除树的一个项目/分支。
问题在于,当我选择和选择项目并且没有孩子时,我必须找到他的父母并删除选择的项目。但是,如果所选项目有孩子,我必须找到他的父母,获取所选项目的所有孩子,更新所有孩子的parentId,添加到父项并删除所选项目。递归地执行所有这些操作并返回更新的数组。
const data = [
{id: 1, title: 'foo', children: [
{id: 11, parentId: 1, title: 'bar',},
{id: 12, parentId: 1, title: 'baz', children: [
{id: 121, parentId: 12, title: 'qux'},
{id: 122, parentId: 12, title: 'quz'}
]},
{id: 13, parentId: 1, title: 'corge'}
]},
{id: 2, title: 'grault'}
];
const id = 12;
console.log (removeElement(data, id));
结果应为:
const data = [
{id: 1, title: 'foo', children: [
{id: 11, parentId: 1, title: 'bar', children: [
{id: 121, parentId: 11, title: 'qux'},
{id: 122, parentId: 11, title: 'quz'}
]},
{id: 13, parentId: 1, title: 'corge'}
]},
{id: 2, title: 'grault'}
];
答案 0 :(得分:2)
尽管这可以通过单个函数完成,但是如果您使用mutual recursion编写代码,它将更加整洁且重复性更低。在这里,我们编写两个函数。可以从数组中删除该元素,将其替换为它可能具有的所有子元素。另一个处理单个对象,并从其中(及其任何子元素中删除ID)。这里的主要功能是removeElement
,如果初始数据是数组,它将在我们的输入上调用removeElementFromArray
或如果初始数据是普通对象,则针对任何子项调用它。
const removeElementFromArray = (arr, id) =>
arr .flatMap (
o => o.id === id
? [... (o .children || []).map (o => removeElement (o, id))]
: [removeElement (o, id)]
)
const removeElement = (obj, id) =>
Array .isArray (obj)
? removeElementFromArray (obj, id)
: {... obj, ... (obj .children ? {children: removeElementFromArray (obj .children, id)} : {}) }
const data = [
{id: 1, title: 'foo', children: [
{id: 11, title: 'bar'},
{id: 12, title: 'baz', children: [
{id: 121, title: 'qux'},
{id: 122, title: 'quz'}
]},
{id: 13, title: 'corge'}
]},
{id: 2, title: 'grault'}
];
console .log (removeElement (data, 121)) // 121 removed
console .log (removeElement (data, 12)) // 12 removed; 121 and 122 moved to 1
console .log (removeElement (data, 1)) // 1 removed; 11, 12, 13 moved to root
console .log (removeElement (data, 42)) // No change
.as-console-wrapper {min-height: 100% !important; top: 0}
答案 1 :(得分:1)
希望这会有所帮助
repeat
答案 2 :(得分:1)
我同意Scott的观点,相互递归非常适合此问题。但是,我将职责划分为略有不同-
const remove = (t = [], id = 0) =>
t.flatMap(v => remove1(v, id))
const remove1 = ({ children = [], ...t }, id = 0) => // "remove one"
t.id === id
? remove(children, id)
: [ { ...t, children: remove(children, id) } ]
const data = [
{id: 1, title: 'foo', children: [
{id: 11, title: 'bar'},
{id: 12, title: 'baz', children: [
{id: 121, title: 'qux'},
{id: 122, title: 'quz'}
]},
{id: 13, title: 'corge'}
]},
{id: 2, title: 'grault'}
];
console.log(remove(data, 121))
console.log(remove(data, 12))
console.log(remove(data, 1))
console.log(remove(data, 42))
.as-console-wrapper {min-height: 100% !important; top: 0}
此外,此答案不太关心可选的children
属性,因此,它将为没有{ ...t, children: [] }
的任何t
添加children
。
我很欣赏Scott的严格方法,我想知道如何才能保留少children
的叶子节点-
const identity = x => x
const update = (t = {}, k = "", f = identity) => // <- immutable update
t[k] == null
? t
: { ...t, [k]: f(t[k]) }
const remove = (t = [], id = 0) =>
t.flatMap(v => remove1(v, id))
const remove1 = (t = {}, id = 0) =>
t.id === id
? remove(t.children, id)
: [ update(t, "children", c => remove(c, id)) ] // <-- update
const data = [
{id: 1, title: 'foo', children: [
{id: 11, title: 'bar'},
{id: 12, title: 'baz', children: [
{id: 121, title: 'qux'},
{id: 122, title: 'quz'}
]},
{id: 13, title: 'corge'}
]},
{id: 2, title: 'grault'}
];
console.log(remove(data, 121))
console.log(remove(data, 12))
console.log(remove(data, 1))
console.log(remove(data, 42))
.as-console-wrapper {min-height: 100% !important; top: 0}