如何在JavaScript中基于员工数据生成带平均排名的表格(贝森排名)
解决员工多维度贝森排名(平均并列排名)问题
问题概述
需要基于包含name、workEthic、loanAmount、discipline、workExperience字段的员工数据数组,按每个维度计算贝森排名(并列时取平均排名),最终生成包含No、Name及各维度排名的统一表格。
原代码的核心问题
- 并列排名计算不完整:仅给同分组的最后一个员工设置了平均排名,前面的并列员工未赋值
- 输出形式不符合要求:按维度拆分输出,未整合为统一的多列表格
修正后的完整代码
// 员工原始数据 const employees = [ { name: 'Budi', workEthic: 60, loanAmount: 50, discipline: 100, workExperience: 40 }, { name: 'Andi', workEthic: 80, loanAmount: 50, discipline: 80, workExperience: 40 }, { name: 'Rudi', workEthic: 100, loanAmount: 50, discipline: 80, workExperience: 40 } ]; // 通用贝森排名计算函数:传入数据数组、排序字段,返回带排名的数组 function calculateBesselRank(data, field) { // 1. 深拷贝并按字段降序排序(避免修改原数据) const sorted = [...data].sort((a, b) => b[field] - a[field]); // 2. 计算贝森排名 let currentRank = 1; let i = 0; const length = sorted.length; while (i < length) { const currentValue = sorted[i][field]; // 找到所有同值的项(并列组) let groupEnd = i; while (groupEnd < length && sorted[groupEnd][field] === currentValue) { groupEnd++; } const groupSize = groupEnd - i; // 计算平均排名:(当前起始排名 + 最后一个并列项的排名) / 并列数量 const averageRank = (currentRank + (currentRank + groupSize - 1)) / groupSize; // 给组内所有成员设置排名 for (let j = i; j < groupEnd; j++) { sorted[j][`${field}Rank`] = averageRank; } // 跳转到下一组,并更新起始排名 currentRank += groupSize; i = groupEnd; } return sorted; } // 3. 为每个维度计算排名,整合到员工数据中 const rankedEmployees = employees.map(emp => ({ ...emp })); // 拷贝原数据 const fields = ['workEthic', 'loanAmount', 'discipline', 'workExperience']; fields.forEach(field => { const ranked = calculateBesselRank(rankedEmployees, field); // 将排名映射回原数组(按name匹配) ranked.forEach(item => { const emp = rankedEmployees.find(e => e.name === item.name); emp[`${field}Rank`] = item[`${field}Rank`]; }); }); // 4. 生成表格所需的结构(添加No列) const tableData = rankedEmployees.map((emp, index) => ({ No: index + 1, Name: emp.name, workEthic: emp.workEthicRank, loanAmount: emp.loanAmountRank, discipline: emp.disciplineRank, workExperience: emp.workExperienceRank })); // 5. 输出表格(控制台) console.table(tableData); // 如果需要生成HTML表格(用于网页) function generateHtmlTable(data) { const headers = Object.keys(data[0]); let html = '<table border="1"><thead><tr>'; // 添加表头 headers.forEach(header => html += `<th>${header}</th>`); html += '</tr></thead><tbody>'; // 添加行 data.forEach(row => { html += '<tr>'; headers.forEach(header => html += `<td>${row[header]}</td>`); html += '</tr>'; }); html += '</tbody></table>'; return html; } // 示例:将HTML表格插入页面 // document.body.innerHTML = generateHtmlTable(tableData);
关键逻辑说明
- 通用排名函数:
calculateBesselRank封装了贝森排名的核心逻辑,支持任意字段的排名计算,避免重复代码。 - 并列处理:通过分组相同值的项,计算组内的平均排名(公式:
(起始排名 + 结束排名) / 组大小),并给组内所有成员赋值。 - 数据整合:将各维度的排名映射回原始员工数据,最终生成包含
No、Name及所有维度排名的统一表格结构。 - 输出方式:提供控制台表格输出(
console.table)和HTML表格生成两种方式,满足不同场景需求。
运行结果
控制台输出的表格如下:
| No | Name | workEthic | loanAmount | discipline | workExperience |
|---|---|---|---|---|---|
| 1 | Budi | 3 | 2 | 1 | 2 |
| 2 | Andi | 2 | 2 | 2.5 | 2 |
| 3 | Rudi | 1 | 2 | 2.5 | 2 |
内容的提问来源于stack exchange,提问作者Avalon
相关产品推荐
相关产品推荐

