Один проход, но в каждом узле будет
children
даже если пустой:
function unFlatten(array) {
const childrenMap = Object.create(null);
for(const item of array) {
if(item.parent in childrenMap)
childrenMap[item.parent].push(item);
else
childrenMap[item.parent] = [item];
if(!childrenMap[item.id]) childrenMap[item.id] = [];
item.children = childrenMap[item.id];
};
return childrenMap[null]
}
Один-два прохода, как повезёт, но
children
только там где нужны.
function unFlatten(array) {
const childrenMap = Object.create(null);
const secondPass = [];
for(const item of array) {
if(item.parent in childrenMap)
childrenMap[item.parent].push(item);
else
childrenMap[item.parent] = [item];
if(item.id in childrenMap)
item.children = childrenMap[item.id];
else
secondPass.push(item)
};
for(const item of secondPass) {
if(item.id in childrenMap)
item.children = childrenMap[item.id];
};
return childrenMap[null]
}
Или от обратного:
function unFlatten(array) {
const map = Object.create(null);
const secondPass = [];
for(const item of array) {
map[item.id] = item;
if(item.parent in map) {
if('children' in map[item.parent])
map[item.parent].children.push(item)
else
map[item.parent].children = [item];
} else {
secondPass.push(item);
}
};
for(const item of secondPass) {
if(item.parent in map) {
if('children' in map[item.parent])
map[item.parent].children.push(item)
else
map[item.parent].children = [item];
}
};
return secondPass
}
Любой вариант меняет исходные узлы(если надо - клонируйте), и не рассматривает случай когда цепочка родитель-потомок может быть сломана.