Scala:基于内部对象列表对学生数据进行分组
问题描述
现有如下格式的学生对象列表:
[ { studentId: "a1", std: "10", isEligible: true, completedProjectInfo: [ { projectNumber: "c1", projectName: "AAT", projectCompletedPlaces: { count: 2, city: ["Mumbai", "Delhi"] } } ] }, { studentId: "a2", std: "10", isEligible: false, completedProjectInfo: [ { projectNumber: "c3", projectName: "AAK", projectCompletedPlaces: { count: 1, city: ["Mumbai"] } } ] }, { studentId: "a3", std: "10", isEligible: false, completedProjectInfo: [ { projectNumber: "c3", projectName: "AAK", projectCompletedPlaces: { count: 1, city: ["Mumbai"] } } ] }, { studentId: "a4", std: "10", isEligible: true, completedProjectInfo: [ { projectNumber: "c1", projectName: "AAT", projectCompletedPlaces: { count: 2, city: ["Mumbai", "Delhi"] } }, { projectNumber: "c3", projectName: "AAK", projectCompletedPlaces: { count: 1, city: ["Mumbai"] } } ] } ]
需要将除studentId外所有信息完全相同(包括嵌套的completedProjectInfo对象列表)的学生分组,期望结果如下:
[ { commonInfoStudents: ["a2", "a3"], std: "10", isEligible: false, completedProjectInfo: [ { projectNumber: "c3", projectName: "AAK", projectCompletedPlaces: { count: 1, city: ["Mumbai"] } } ] }, { commonInfoStudents: ["a1"], std: "10", isEligible: true, completedProjectInfo: [ { projectNumber: "c1", projectName: "AAT", projectCompletedPlaces: { count: 2, city: ["Mumbai", "Delhi"] } } ] }, { commonInfoStudents: ["a4"], std: "10", isEligible: true, completedProjectInfo: [ { projectNumber: "c1", projectName: "AAT", projectCompletedPlaces: { count: 2, city: ["Mumbai", "Delhi"] } }, { projectNumber: "c3", projectName: "AAK", projectCompletedPlaces: { count: 1, city: ["Mumbai"] } } ] } ]
尝试过用groupBy按std和isEligible分组,但不知道如何处理嵌套对象的比较,求解决方案。
解决方案
核心思路是:为每个学生生成一个唯一标识键,这个键由除studentId外的所有信息(包括嵌套结构)转换而来,确保内容完全相同的学生生成相同的键,再按这个键分组。
步骤1:编写生成唯一键的函数
直接用JSON.stringify会受数组元素顺序影响(比如两个项目列表内容相同但顺序不同会被当成不同键),所以需要先对嵌套的数组进行排序,再序列化:
function generateGroupKey(student) { // 复制学生对象,排除studentId const { studentId, ...rest } = student; // 处理completedProjectInfo数组:按projectNumber排序,同时排序每个项目里的city数组 const sortedProjects = [...rest.completedProjectInfo].sort((a, b) => a.projectNumber.localeCompare(b.projectNumber) ).map(project => { const sortedCity = [...project.projectCompletedPlaces.city].sort(); return { ...project, projectCompletedPlaces: { ...project.projectCompletedPlaces, city: sortedCity } }; }); // 替换排序后的项目列表 const normalizedRest = { ...rest, completedProjectInfo: sortedProjects }; // 序列化为字符串作为分组键 return JSON.stringify(normalizedRest); }
步骤2:使用reduce进行分组
遍历学生列表,按生成的键分组,收集对应的studentId:
const students = [/* 原始学生数据 */]; // 分组:键是生成的唯一标识,值是包含studentId和公共信息的对象 const grouped = students.reduce((acc, student) => { const key = generateGroupKey(student); if (!acc[key]) { // 首次遇到该键,初始化分组:保存公共信息和studentId数组 const { studentId, ...commonInfo } = student; acc[key] = { commonInfoStudents: [studentId], ...commonInfo }; } else { // 已有分组,添加studentId acc[key].commonInfoStudents.push(student.studentId); } return acc; }, {}); // 将分组结果转换为数组形式 const result = Object.values(grouped);
步骤3:验证结果
执行上述代码后,result就是期望的分组格式。这个方案能处理嵌套对象和数组的比较,即使数组元素顺序不同,只要内容一致就会被分到同一组。
内容的提问来源于stack exchange,提问作者lets code
相关产品推荐
相关产品推荐

