如何按嵌套数组内对象属性分组数组(Vanilla JS/Lodash实现)
按嵌套数组对象属性分组任务(原生JS/Lodash实现)
问题背景
需要将包含多经办人的任务数组,按每个经办人分组,让每个经办人对应自己的任务列表(仅包含任务标题和状态)。示例数据如下:
const taskList = [ { "assignees": [ { "name": "John", "uid": "id0001" }, { "name": "Sally", "uid": "id0002" } ], "title": "Task 1", "status": "To do" }, { "assignees": [{ "name": "John", "uid": "id0001" }], "title": "Task 2", "status": "To do" }, { "assignees": [{ "name": "Sally", "uid": "id0002" }], "title": "Task 3", "status": "To do" } ];
期望得到的分组结果:
{ "id0001": { "name": "John", "tasks": [ { "title": "Task 1", "status": "To do" }, { "title": "Task 2", "status": "To do" } ] }, "id0002": { "name": "Sally", "tasks": [ { "title": "Task 1", "status": "To do" }, { "title": "Task 3", "status": "To do" } ] } }
原代码问题分析
你之前用_.groupBy(taskList, task => task.assignees)失败的原因是:task.assignees是对象数组,JavaScript会自动将对象转换为字符串[object Object],导致所有任务被分到同一个分组下。
原生JavaScript实现
使用Array.prototype.reduce遍历任务列表,嵌套遍历每个经办人,逐步构建目标结构:
const groupedByAssignee = taskList.reduce((acc, task) => { // 遍历当前任务的所有经办人 task.assignees.forEach(assignee => { const taskInfo = { title: task.title, status: task.status }; // 初始化经办人分组(若不存在) if (!acc[assignee.uid]) { acc[assignee.uid] = { name: assignee.name, tasks: [] }; } // 将任务添加到对应经办人的列表中 acc[assignee.uid].tasks.push(taskInfo); }); return acc; }, {});
Lodash实现
通过展平任务-经办人关系→按UID分组→整理结构三步完成,也可以用链式调用简化:
链式调用版本
const result = _(taskList) // 展平:每个任务与每个经办人生成独立条目 .flatMap(task => task.assignees.map(assignee => ({ assignee, task }))) // 按经办人UID分组 .groupBy('assignee.uid') // 整理成期望的结构 .mapValues(items => ({ name: items[0].assignee.name, tasks: items.map(({ task }) => ({ title: task.title, status: task.status })) })) // 获取最终结果 .value();
分步拆解版本
// 1. 展平任务与经办人的对应关系 const flattened = _.flatMap(taskList, task => { return task.assignees.map(assignee => ({ assignee, taskInfo: { title: task.title, status: task.status } })); }); // 2. 按经办人UID分组 const grouped = _.groupBy(flattened, item => item.assignee.uid); // 3. 整理为目标结构 const result = _.mapValues(grouped, items => ({ name: items[0].assignee.name, tasks: items.map(item => item.taskInfo) }));
内容的提问来源于stack exchange,提问作者ReactSwift
相关产品推荐
相关产品推荐

