如何在JavaScript中通过排序实现数组的父子分组排列?
数组排序分组问题求解
需要实现数组元素的排序分组,规则如下:
- 优先排列uniqueID非空且parentDocId为空的父元素,每个父元素紧随其后排列所有
parentDocId等于该父元素uniqueID的子元素 - 没有对应子元素的
parentDocId为空的元素,需放在数组末尾
预期输出
[ { name: 9, uniqueID: '22222', parentDocId: '', }, { name: 11, uniqueID: '3463452345', parentDocId: '22222', }, { name: 15, uniqueID: '3333', parentDocId: '', }, { name: 19, uniqueID: '234235346', parentDocId: '3333', }, { name: 346345, uniqueID: '11111', parentDocId: '', }, { name: 7, uniqueID: '456456456', parentDocId: '11111', }, { name: 55, uniqueID: '346345345', parentDocId: '', }, { name: 77, uniqueID: '568567568567', parentDocId: '', }, ];
实际输出
[ { "name": 55, "uniqueID": "346345345", "parentDocId": "" }, { "name": 77, "uniqueID": "568567568567", "parentDocId": "" }, { "name": 7, "uniqueID": "456456456", "parentDocId": "11111" }, { "name": 346345, "uniqueID": "11111", "parentDocId": "" }, { "name": 19, "uniqueID": "234235346", "parentDocId": "3333" }, { "name": 15, "uniqueID": "3333", "parentDocId": "" }, { "name": 11, "uniqueID": "3463452345", "parentDocId": "22222" }, { "name": 9, "uniqueID": "22222", "parentDocId": "" } ]
当前代码
items.sort((a, b) => { if (a.parentDocId === b.uniqueID) { return -1; } else if (b.parentDocId === a.uniqueID) { return 1; } else if (a.parentDocId === '' && b.parentDocId !== '') { return -1; } else if (a.parentDocId !== '' && b.parentDocId === '') { return 1; } else { return 0; } });
问题分析
当前排序逻辑仅处理了相邻元素的父子关系,无法将父元素与对应子元素整体归组,也未区分有子元素的父和无子元素的父的优先级,导致子元素跑到父元素前面,且无子的父元素排在了最前面,不符合需求。
解决方案
采用分类拼接的方式更直观,逻辑清晰且不易出错:
// 1. 分离父元素(parentDocId为空且uniqueID非空)和子元素 const parents = items.filter(item => item.parentDocId === '' && item.uniqueID); const children = items.filter(item => item.parentDocId !== ''); // 2. 建立父元素到其子元素的映射 const parentChildrenMap = new Map(); children.forEach(child => { if (!parentChildrenMap.has(child.parentDocId)) { parentChildrenMap.set(child.parentDocId, []); } parentChildrenMap.get(child.parentDocId).push(child); }); // 3. 拆分父元素为「有子元素的父」和「无子元素的父」 const parentsWithChildren = parents.filter(p => parentChildrenMap.has(p.uniqueID)); const parentsWithoutChildren = parents.filter(p => !parentChildrenMap.has(p.uniqueID)); // 4. 构建最终结果:有子的父+对应子元素,再拼接无子的父 const sortedItems = []; parentsWithChildren.forEach(parent => { sortedItems.push(parent); sortedItems.push(...parentChildrenMap.get(parent.uniqueID)); }); sortedItems.push(...parentsWithoutChildren);
如果需要保持原数组中父元素的相对顺序,上述代码中的filter方法会保留原数组的遍历顺序,完全匹配预期输出的排列逻辑。
内容的提问来源于stack exchange,提问作者Saint-Fons
相关产品推荐
相关产品推荐

