Given a flat array of objects, I group the children items by pid (parent id) to the id's of the parents. My function does exactly that, but only two levels deep. How could I turn this function into a function that handles nesting of any depth?
This is the data:
const list =
[
{ "pid": 0, "id": "solo"},
{ "pid": 0, "id": "member"},
{ "pid": 0, "id": "solo2"},
{ "pid": "member", "id": "10_admin_members"},
{ "pid": "member", "id": "10_invitations"},
{ "pid": "member", "id": "sub_member"},
{ "pid": "sub_member", "id": "other"},
{ "pid": "sub_member", "id": "other2"},
{ "pid": 0, "id": "admin"},
{ "pid": "admin", "id": "admin_general"},
{ "pid": "admin", "id": "admin_modules"},
{ "pid": "admin", "id": "admin_roles"},
{ "pid": "admin", "id": "admin_navigation"},
]
And the function:
const groupChildrenToParentsByKeys = (firstLevelItems, groupedItems, childArrayKey = 'items')
=> {
let cleanArray = []
for (const a in firstLevelItems) {
let childrenCount = 0
for (const b in groupedItems) {
if(firstLevelItems[a].id == b) {
let descendantsArray = []
let childrenArray = groupedItems[b]
for (const c in childrenArray) {
let grandChildrenCount = 0
for (const h in groupedItems) {
if(childrenArray[c].id == h) {
let grandChildrenArray = groupedItems[h]
descendantsArray.push({...childrenArray[c], [childArrayKey]: grandChildrenArray})
grandChildrenCount ++
}
}
if(!grandChildrenCount) {
descendantsArray.push(childrenArray[c])
}
}
cleanArray.push({...firstLevelItems[a], [childArrayKey]: descendantsArray})
childrenCount ++
}
}
if(!childrenCount) {
cleanArray.push(firstLevelItems[a])
}
}
return cleanArray
}
const list =
[
{ "pid": 0, "id": "solo"},
{ "pid": 0, "id": "member"},
{ "pid": 0, "id": "solo2"},
{ "pid": "member", "id": "10_admin_members"},
{ "pid": "member", "id": "10_invitations"},
{ "pid": "member", "id": "sub_member"},
{ "pid": "sub_member", "id": "other"},
{ "pid": "sub_member", "id": "other2"},
{ "pid": 0, "id": "admin"},
{ "pid": "admin", "id": "admin_general"},
{ "pid": "admin", "id": "admin_modules"},
{ "pid": "admin", "id": "admin_roles"},
{ "pid": "admin", "id": "admin_navigation"},
]
// Matches two objects by keys and inserts the children inside of parents as array
const groupChildrenToParentsByKeys = (firstLevelItems, groupedItems, childArrayKey = 'items') => {
let cleanArray = []
for (const a in firstLevelItems) {
let childrenCount = 0
for (const b in groupedItems) {
if(firstLevelItems[a].id == b) {
let descendantsArray = []
let childrenArray = groupedItems[b]
for (const c in childrenArray) {
let grandChildrenCount = 0
for (const h in groupedItems) {
if(childrenArray[c].id == h) {
let grandChildrenArray = groupedItems[h]
descendantsArray.push({...childrenArray[c], [childArrayKey]: grandChildrenArray})
grandChildrenCount ++
}
}
if(!grandChildrenCount) {
descendantsArray.push(childrenArray[c])
}
}
cleanArray.push({...firstLevelItems[a], [childArrayKey]: descendantsArray})
childrenCount ++
}
}
if(!childrenCount) {
cleanArray.push(firstLevelItems[a])
}
}
return cleanArray
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
let groupedObject = _.groupBy(list, 'pid')
let firstLevel = {...groupedObject}[0]
let childrenParentArray = groupChildrenToParentsByKeys(firstLevel, groupedObject)
console.log(JSON.stringify(childrenParentArray, null, 2))
console.log(_.size(childrenParentArray))
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js"></script>