I have a one dimensional array of objects and each object has an id and an id of its parent. In the initial array I have each element can have at most one child. So if the array looks like this:
{id: 3, parent: 5},
{id: 5, parent: null},
{id: 6, parent: 3},
{id: 1, parent: null},
{id: 4, parent: 7},
{id: 2, parent: 1},
{id: 7, parent: 2}
I need it to look similar to this:
{id: 5, parent: null, children: [
{id: 3, parent: 5},
{id: 6, parent: 3}
]},
{id: 1, parent: null, children: [
{id: 2, parent: 1},
{id: 7, parent: 2},
{id: 4, parent: 7},
]}
I think the way I did it uses too much loops. Is there a better way?
let items = [ {id: 3, parent: 5}, {id: 5, parent: null}, {id: 6, parent: 3}, {id: 1, parent: null}, {id: 4, parent: 7}, {id: 2, parent: 1}, {id: 7, parent: 2} ]; let itemsNew = []; items = items.map(function(x){ return {id: x.id, parent: x.parent, children: []}; }); // new array with parents only for(let i=items.length-1; i>=0; i--){ if(items[i].parent == null){ itemsNew.push(items[i]); items.splice(i, 1); } } for(let i=0; i<itemsNew.length; i++){ let childIndexes = findChildAll(itemsNew[i].id); // sort the indexes so splicing the array wont misplace them childIndexes.sort(function(a,b){ return ba; }); for(let j=0; j<childIndexes.length; j++){ itemsNew[i].children.push(items[childIndexes[j]]); items.splice(childIndexes[j], 1); } } // returns an array of indexes of all the element's children and their children function findChildAll(parentId){ for(let i=0; i<items.length; i++){ if(items[i].parent == parentId){ let resultArray = findChildAll(items[i].id); // is the result as an array add it to the index if(resultArray) return [i].concat(resultArray); // otherwise return just this index return [i]; } } } console.log(itemsNew);
You could simplify it a lot by utilizing filter
:
for(const item of items)
item.children = items.filter(child => child.parent === item.id);
const parents = items.filter(item => !item.parent);
Or if there are lots of nodes, might be benefitial for performance to use a Map:
const itemsByID = new Map(items.map(item => [item.id, item]));
const parents = [];
for(const item of items) {
if(item.parent) {
const parent = itemsByID[item.parent];
if(!parent.children) parent.children = [];
parent.children.push(item);
} else parents.push(item);
}
finding the children could be slow if the array gets big because the function searches always in the full array
const withParent = items.filter((item) => item.parent !== null);
const getDeepIdsWithId = (id) => {
const result = [];
while (true) {
const i = withParent.find((item) => item.parent === id);
if (!i) {
break;
}
id = i.id;
result.push(i);
}
return result;
};
const parent = items.filter((item) => item.parent === null).map((item) => ({...item, children: getDeepIdsWithId(item.id)}));
I think you can take a recursive approach some like this:
const array1 = [{id: 3, parent: 5},
{id: 5, parent: null},
{id: 6, parent: 3},
{id: 1, parent: null},
{id: 4, parent: 7},
{id: 2, parent: 1},
{id: 7, parent: 2}];
const getChild = (origi, fathers) =>
origi.filter(
originEle => originEle.parent && fathers.some(f => f.id === originEle.parent)
)
const getChildren = (originArray, fathers) => {
let childs = getChild(originArray, fathers);
let continueFetching = childs && childs.length > 0;
while (continueFetching) {
const moreChilds = getChild(originArray, childs)
.filter(m => !childs.some(c => c.id === m.id))
if (
moreChilds &&
moreChilds.length > 0
) {
childs = childs.concat(moreChilds);
continueFetching = true;
} else {
continueFetching = false;
}
}
return childs;
}
const result = array1
.filter(
a1 => !a1.parent
)
.map(
aFather => ({
id: aFather.id,
parent: null,
children: getChildren(array1, [aFather])
})
)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.