通过键对对象数组进行分组。如何处理任何深度的后代?
Grouping array of objects items by keys. How to handle any depth of decendants?
给定一个平面对象数组,我按 pid(父 ID)将子项分组到父项的 ID。我的函数正是这样做的,但只有两层深。我怎样才能把这个函数变成一个处理任何深度嵌套的函数?
这是数据:
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"},
]
以及函数:
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>
进行一次循环,同时为 parent/children 和 children/parent 创建一个关系。结果,您得到一棵依赖于关系而不是数据顺序的树。
const
getTree = (data, root) => {
const t = {};
data.forEach(o =>
((t[o.pid] ??= {}).items ??= []).push(Object.assign(t[o.id] ??= {}, o))
);
return t[root].items;
},
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" }],
tree = getTree(list, 0);
console.log(tree);
.as-console-wrapper { max-height: 100% !important; top: 0; }
给定一个平面对象数组,我按 pid(父 ID)将子项分组到父项的 ID。我的函数正是这样做的,但只有两层深。我怎样才能把这个函数变成一个处理任何深度嵌套的函数?
这是数据:
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"},
]
以及函数:
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>
进行一次循环,同时为 parent/children 和 children/parent 创建一个关系。结果,您得到一棵依赖于关系而不是数据顺序的树。
const
getTree = (data, root) => {
const t = {};
data.forEach(o =>
((t[o.pid] ??= {}).items ??= []).push(Object.assign(t[o.id] ??= {}, o))
);
return t[root].items;
},
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" }],
tree = getTree(list, 0);
console.log(tree);
.as-console-wrapper { max-height: 100% !important; top: 0; }