Reputation: 151
I have this JSON object:
items = [
{id: 1, name: "home", parent: 0, active: 1, order: 0},
{id: 2, name: "dashboard", parent: 0, active: 1, order: 1},
{id: 3, name: "report1", parent: 2, active: 1, order: 11},
{id: 4, name: "analytics", parent: 0, active: 1, order: 2},
{id: 5, name: "report2", parent: 2, active: 1, order: 21},
{id: 6, name: "report3", parent: 2, active: 1, order: 22},
{id: 7, name: "analytics_page1", parent: 4, active: 1, order: 23}
]
I want to filter it by parent, keeping any with a parent number of 0, and moving any values with a parent number that matches the id into its children. So I want something like this:
itemsUpdated= [
{ id: 1,
name: "home",
parent: 0,
active: 1,
order: 0,
children:[]
},
{ id: 2,
name: "dashboard",
parent: 0,
active: 1,
order: 1,
children:[
{id: 3, name: "report1", parent: 2, active: 1, order: 11, children: []},
{id: 5, name: "report2", parent: 2, active: 1, order: 21, children:[]},
{id: 6, name: "report3", parent: 2, active: 1, order: 22, children:[]}
]
},
{ id: 4,
name: "analytics",
parent: 0,
active: 1,
order: 2,
children:[
{id: 7, name: "analytics_page1", parent: 4, active: 1, order: 23, children:[]}
]
}
]
so far I have managed to add a children key with an empty array to every item:
let itemsUpdated = items;
for(let i = 0 ; i < itemsUpdated .length; i++){
itemsUpdated [i].children = [];
}
//MY UPDATED ITEMS LOOKS LIKE THIS
updatedItems = [
{id: 1, name: "home", parent: 0, active: 1, order: 0, children:[]},
{id: 2, name: "dashboard", parent: 0, active: 1, order: 1, children:[]},
{id: 3, name: "report1", parent: 2, active: 1, order: 11, children:[]},
{id: 4, name: "analytics", parent: 0, active: 1, order: 2, children:[]},
{id: 5, name: "report2", parent: 2, active: 1, order: 21, children:[]},
{id: 6, name: "report3", parent: 2, active: 1, order: 22, children:[]},
{id: 7, name: "analytics_page1", parent: 4, active: 1, order: 23, children:[]}
]
How would I go about filtering and reducing this array down ?
Upvotes: 2
Views: 474
Reputation: 12953
This is a case for reduce()
, accumulating each object into the children
array of its parent indexed by id
in the accumulator object. The result is the array stored in the ['0']
property of the returned object.
The advantage of this over some of the other approaches is that it doesn't employ nested loops.
(items array edited from question to include nested children: id: 7
is a child of id: 6
)
const items = [
{ id: 3, name: "report1", parent: 2, active: 1, order: 11 },
{ id: 1, name: "home", parent: 0, active: 1, order: 0 },
{ id: 2, name: "dashboard", parent: 0, active: 1, order: 1 },
{ id: 4, name: "analytics", parent: 0, active: 1, order: 2 },
{ id: 5, name: "report2", parent: 2, active: 1, order: 21 },
{ id: 6, name: "report3", parent: 2, active: 1, order: 22 },
{ id: 7, name: "analytics_page1", parent: 6, active: 1, order: 23 }
]
const result = items.reduce((a, o) => {
a[o.id] = a[o.id] || [];
a[o.parent] = a[o.parent] || [];
a[o.parent].push({ ...o, children: a[o.id] });
return a;
}, {})['0'];
console.log(JSON.stringify(result, null, 2));
.as-console-wrapper { max-height: 100% !important; top: 0; }
A little more concise using logical nullish assignment (??=)
const items = [
{ id: 3, name: "report1", parent: 2, active: 1, order: 11 },
{ id: 1, name: "home", parent: 0, active: 1, order: 0 },
{ id: 2, name: "dashboard", parent: 0, active: 1, order: 1 },
{ id: 4, name: "analytics", parent: 0, active: 1, order: 2 },
{ id: 5, name: "report2", parent: 2, active: 1, order: 21 },
{ id: 6, name: "report3", parent: 2, active: 1, order: 22 },
{ id: 7, name: "analytics_page1", parent: 6, active: 1, order: 23 }
]
const result = items
.reduce((a, o) => (
(a[o.parent] ??= []).push({ ...o, children: (a[o.id] ??= []) }), a), {}
)['0'];
console.log(JSON.stringify(result, null, 2));
.as-console-wrapper { max-height: 100% !important; top: 0; }
Upvotes: 1
Reputation: 840
I also want to submit my trial with recursion in mind for nested children, you can see the example of id: 4
let items = [
{ id: 1, name: "home", parent: 0, active: 1, order: 0 },
{ id: 2, name: "dashboard", parent: 0, active: 1, order: 1 },
{ id: 3, name: "report1", parent: 2, active: 1, order: 11 },
{ id: 4, name: "analytics", parent: 3, active: 1, order: 2 },
{ id: 5, name: "report2", parent: 2, active: 1, order: 21 },
{ id: 6, name: "report3", parent: 2, active: 1, order: 22 },
{ id: 7, name: "analytics_page1", parent: 4, active: 1, order: 23 }
];
//adds children empty array
items.forEach((item) => {
item.children = [];
return item;
});
//filters parents on 0 level first
let newItems = items.filter((item) => item.parent === 0);
//recursion
items.forEach((item) => searchParent(newItems, item));
console.log(newItems);
function searchParent(someArray, childObject) {
someArray.forEach((parent) => {
if (parent.id === childObject.parent) {
parent.children.push(childObject);
} else {
if (parent.children) searchParent(parent.children, childObject);
}
});
}
Upvotes: 0
Reputation: 11
const items = [
{ id: 1, name: 'home', parent: 0, active: 1, order: 0 },
{ id: 2, name: 'dashboard', parent: 0, active: 1, order: 1 },
{ id: 3, name: 'report1', parent: 2, active: 1, order: 11 },
{ id: 4, name: 'analytics', parent: 0, active: 1, order: 2 },
{ id: 5, name: 'report2', parent: 2, active: 1, order: 21 },
{ id: 6, name: 'report3', parent: 2, active: 1, order: 22 },
{ id: 7, name: 'analytics_page1', parent: 4, active: 1, order: 23 }
];
const itemsUpdated = items
.filter(el => !el.parent)
.map((el, idx) => {
el.children = [];
items.forEach(e => {
if (e.parent === idx+1) {
el.children.push(e);
}
});
return el;
});
console.log(itemsUpdated);
Upvotes: 0
Reputation: 4337
ik, ik, im the latest to answer but this was a really fun question :D
let items = [
{id: 1, name: "home", parent: 0, active: 1, order: 0},
{id: 2, name: "dashboard", parent: 0, active: 1, order: 1},
{id: 3, name: "report1", parent: 2, active: 1, order: 11},
{id: 4, name: "analytics", parent: 0, active: 1, order: 2},
{id: 5, name: "report2", parent: 2, active: 1, order: 21},
{id: 6, name: "report3", parent: 2, active: 1, order: 22},
{id: 7, name: "analytics_page1", parent: 4, active: 1, order: 23}
]
//I assume you wont want the original items(since with reference logic.. some editing to this will be done)
let itemsUpdated = items //turn this line into 'let itemsUpdated = JSON.parse(JSON.stringify(items))' if you don't want items edited
//firstly a finder function to return elements which parents match an id n
function findMatches(n){
let arr=[]
itemsUpdated.forEach(a=>{if(a.parent==n){arr.push(a)}})
return arr
}
//now to link >:D
itemsUpdated.forEach(a=>{
a.children=[] //your for loop's equivalent :D
let matches=findMatches(a.id)
if(matches.length){
matches.forEach(b=>{a.children.push(b)})
}
})
//now to filter as the finishing touch
itemsUpdated=itemsUpdated.filter(a=>a.parent==0)
console.log(itemsUpdated)
Upvotes: 0