I can't figure out how to explain this right, but I wanna make a function that takes this array:
const tasks = [
{id: 1, goal: 'Clean apartment', parent_id: null},
{id: 2, goal: 'Clean bathroom', parent_id: 1},
{id: 3, goal: 'Clean kitchen', parent_id: 1},
{id: 4, goal: 'Clean sink', parent_id: 2},
{id: 5, goal: 'Clean shower', parent_id: 2},
{id: 6, goal: 'Make app', parent_id: null}
]
and generates this object:
{id: 1, goal: 'Clean apartment', parent_id: null, children: [
{id: 2, goal: 'Clean bathroom', parent_id: 1, children: [
{id: 4, goal: 'Clean sink', parent_id: 2, children: []},
{id: 5, goal: 'Clean shower', parent_id: 2, children: []},
]},
{id: 3, goal: 'Clean kitchen', parent_id: 1, children: []},
]},
{id: 6, goal: 'Make app', parent_id: null, children: []}
Edit: So far I made this, but it only returns the first layer of the children:
function addChildren(tasks, id) {
var task = tasks.find(task => task.id === id)
var children = tasks.filter(task => task.parent_id === id)
task.children = children
return task
}
var newTask = addChildren(tasks, 1)
console.log(newTask)
EDIT 2: I tried making the function recursive, but I get an error saying "tasks.find is not a function".
function addChildren(tasks, id) {
var task = tasks.find(task => task.id === id)
var children = tasks.filter(task => task.parent_id === id)
task.children = children
task.children.forEach(child => {
addChildren(child, child.id)
})
return task
}
var newTask = addChildren(tasks, 1)
console.log(newTask)
CodePudding user response:
Make the function recursive and call it for each child.
const tasks = [
{id: 1, goal: 'Clean apartment', parent_id: null},
{id: 2, goal: 'Clean bathroom', parent_id: 1},
{id: 3, goal: 'Clean kitchen', parent_id: 1},
{id: 4, goal: 'Clean sink', parent_id: 2},
{id: 5, goal: 'Clean shower', parent_id: 2},
{id: 6, goal: 'Make app', parent_id: null}
]
function addChildren(tasks, idOrTask) {
var task = (typeof idOrTask === 'number') ? tasks.find(task => task.id === idOrTask) : idOrTask;
var children = tasks.filter(t => t.parent_id === task.id);
task.children = children.map(child => addChildren(tasks, child));
return task
}
var newTask = addChildren(tasks, 1)
console.log(newTask)
I've optimized the function a little to avoid unnecessary calls of find
.
CodePudding user response:
You can filter those that match a given id, and calculate their children with a recursive call:
const nest = (xs, parent = null) =>
xs .filter (({parent_id}) => parent_id == parent)
.map (({id, ...rest}) => ({id, ...rest, children: nest (xs, id)}))
const tasks = [{id: 1, goal: 'Clean apartment', parent_id: null}, {id: 2, goal: 'Clean bathroom', parent_id: 1}, {id: 3, goal: 'Clean kitchen', parent_id: 1}, {id: 4, goal: 'Clean sink', parent_id: 2}, {id: 5, goal: 'Clean shower', parent_id: 2}, {id: 6, goal: 'Make app', parent_id: null}]
console .log (nest (tasks))
.as-console-wrapper {max-height: 100% !important; top: 0}
If you no longer want the now-redundant parent_id
in the output, you can simply remove it by replacing the map
line above with:
.map (({id, parent_id, ...rest}) => ({id, ...rest, children: nest (xs, id)}))
CodePudding user response:
const tasks = [
{id: 1, goal: 'Clean apartment', parent_id: null},
{id: 2, goal: 'Clean bathroom', parent_id: 1},
{id: 3, goal: 'Clean kitchen', parent_id: 1},
{id: 4, goal: 'Clean sink', parent_id: 2},
{id: 5, goal: 'Clean shower', parent_id: 2},
{id: 6, goal: 'Make app', parent_id: null}
]
function buildTree(root) {
return {
goal: root.goal, // Store the goal
children: tasks
.filter(task => task.parent_id === root.id) // All tasks with parent_id = root.id
.map(child => buildTree(child)) // Recursively collect their children
}
}
const result = buildTree(tasks[0]) // Build the tree starting with 'Clean apartment'
console.log(result);
You can simplify the logic somewhat by not passing around IDs
CodePudding user response:
Why is recursivity a requirement? You can use this iterative way
function buildTree(tasks) {
const tasksById = tasks.reduce((acc, task) => ({
...acc,
[task.id]: { ...task }
}), {})
return Object.values(tasksById).reduce((tree, task) => {
const parent = tasksById[task.parent_id]
if (!parent) {
return tree.concat(task)
}
parent.children = parent.children || []
parent.children.push(task)
return tree
}, [])
}