如何优化对象数组与多数组的属性比对逻辑,返回匹配/不匹配数组
优化学生数据匹配与存储性能方案
需求背景
现有学生对象数组如下:
[ { studentName: 'Vishesh Kumar', dateOfBirth: '14-03-2023', parentName: 'Lalu Kumar', examName: 'UPSC CDS', dateOfExam: '14-03-1998', centerName: 'St Annas High School', centerCode: 'RN1001', studentEmail: 'Visheshkumar@Gmail.in', studentPhoneNumber: 999043139, address: 'D-31,Sectory-73,Noida Up India', city: 'Noida', state: 'UTTAR PRADESH', zipcode: 201301 }, { studentEnrollmentID: 'EN1000006', studentName: 'Arnav Singh', dateOfBirth: '14-03-2023', parentName: 'Arun Singh', examName: 'UPSC CDS', dateOfExam: '14-03-1998', centerName: 'St Annas High School', centerCode: 'RN1001', studentEmail: 'ArnavSingh@Gmail.in', studentPhoneNumber: 6990433540, address: 'D-31,Sectory-44,Noida Up India', city: 'Noida', state: 'UTTAR PRADESH', zipcode: 201301 }, { studentEnrollmentID: 'EN1000004', studentName: 'Sanjay Singh', dateOfBirth: '14-03-2023', parentName: 'Mohan Singh', examName: 'UPSC CDS', dateOfExam: '14-03-1998', centerName: 'St Peters High School', centerCode: 'RN1003', studentEmail: 'SanjaySingh@Gmail.in', StudentPhoneNumber: 9990433538, address: 'D-31,Sectory-53,Noida Up India', city: 'Noida', state: 'UTTAR PRADESH', zipcode: 201301 } ]
需要将每个学生对象的centerName与以下数组比对,centerCode与另一数组比对:
const centerNames = ['St Annas High School', 'KV Music School'] const centerCodes = ['RN1001','RN1002']
最终要返回两个新数组:
- 第一个数组:包含同时满足
centerName在centerNames中且centerCode在centerCodes中的学生对象 - 第二个数组:包含未匹配其中一个或两个条件的学生对象
现有问题
当前采用嵌套for循环+if-else的实现方式,且串行处理异步存储操作,在数组规模增大时性能极差:
for (student of students) { if (student.examCode == examCode) { const newStudent = await new Student(student); await newStudent.save().then(async (result: any) => { studentsUploaded.push(result); }).catch(async (error: any) => { studentsRejected.push(newStudent); errors.push(error); }); } else { studentsRejected.push(student); errors.push(`${examCode} does not match`); } }
优化方案
1. 用Set优化匹配查找性能
数组的includes方法是O(n)时间复杂度,转成Set后查找是O(1),大规模数据下效率提升明显:
const validCenterNames = new Set(centerNames); const validCenterCodes = new Set(centerCodes);
2. 单次遍历完成分类
用数组的reduce方法一次遍历完成学生的分类,避免多次循环:
const [matchedStudents, unmatchedStudents] = students.reduce((acc, student) => { const isMatched = validCenterNames.has(student.centerName) && validCenterCodes.has(student.centerCode); if (isMatched) { acc[0].push(student); } else { acc[1].push(student); } return acc; }, [[], []] as [typeof students, typeof students]);
3. 并行处理异步存储操作
原来的串行await会逐个等待存储完成,改用Promise.all并行处理,大幅提升存储效率:
const errors: any[] = []; const studentsUploaded: any[] = []; const studentsRejected: any[] = [...unmatchedStudents]; // 并行处理匹配学生的存储 const savePromises = matchedStudents.map(async (student) => { try { const newStudent = new Student(student); const result = await newStudent.save(); studentsUploaded.push(result); } catch (error) { studentsRejected.push(student); errors.push(error); } }); // 等待所有存储操作完成 await Promise.all(savePromises);
完整优化代码
async function processStudents(students: any[], examCode: string) { // 转Set优化查找 const validCenterNames = new Set(['St Annas High School', 'KV Music School']); const validCenterCodes = new Set(['RN1001','RN1002']); const errors: any[] = []; // 一次遍历分类学生并记录不匹配原因 const [matchedStudents, unmatchedStudents] = students.reduce((acc, student) => { // 同时匹配考点信息和考试编码 const isEligible = validCenterNames.has(student.centerName) && validCenterCodes.has(student.centerCode) && student.examCode === examCode; if (isEligible) { acc[0].push(student); } else { acc[1].push(student); // 精准记录错误原因 if (student.examCode !== examCode) { errors.push(`${examCode} does not match for student ${student.studentName}`); } else { errors.push(`Invalid center info for student ${student.studentName}`); } } return acc; }, [[], []] as [typeof students, typeof students]); const studentsUploaded: any[] = []; const studentsRejected: any[] = [...unmatchedStudents]; // 并行存储匹配的学生 const savePromises = matchedStudents.map(async (student) => { try { const newStudent = new Student(student); const result = await newStudent.save(); studentsUploaded.push(result); } catch (error) { studentsRejected.push(student); errors.push(error); } }); await Promise.all(savePromises); return { studentsUploaded, studentsRejected, errors }; }
优化点说明
- 查找性能:Set的O(1)查找替代数组O(n)查找,数据量越大优势越明显
- 遍历效率:一次遍历完成分类,减少循环次数
- 异步性能:并行处理存储操作,避免串行等待,IO密集型场景下性能提升数倍
内容的提问来源于stack exchange,提问作者paavan
相关产品推荐
相关产品推荐

