已实现overall_rank,如何为对象数组按类别和值添加rank字段?
问题描述
我正在处理如下格式的大型对象数组:
// Sample data const array = [ {country: "Germany", category: "A", value: 300}, {country: "Brazil", category: "A", value: 200}, {country: "Canada", category: "A", value: 200}, {country: "Germany", category: "B", value: 100}, {country: "Brazil", category: "B", value: 400}, {country: "Canada", category: "B", value: 500}, ]
希望为数组元素添加两个字段:
rank:按category分组后,组内按value降序排序的排名(相同值排名相同)overall_rank:不考虑category,按value降序排序的排名(相同值排名相同)
预期结果如下:
// Expected result [ {country: "Germany", category: "A", value: 300, rank: 1, overall_rank: 2}, {country: "Brazil", category: "A", value: 200, rank: 2, overall_rank: 3}, {country: "Canada", category: "A", value: 200, rank: 2, overall_rank: 3}, {country: "Germany", category: "B", value: 100, rank: 3, overall_rank: 4}, {country: "Brazil", category: "B", value: 200, rank: 2, overall_rank: 3}, {country: "Canada", category: "B", value: 500, rank: 1, overall_rank: 1}, ]
目前已成功实现overall_rank的计算,代码如下:
array.sort(function(a, b){ return b.value - a.value; }); var overall_rank = 1; for (var i = 0; i < array.length; i++) { if (i > 0 && array[i].value < array[i - 1].value) { overall_rank++; } array[i].overall_rank = overall_rank; }
但在按类别和值计算rank字段时遇到困难,请问该如何推进?
解决方案
要计算分组内的rank,核心思路是先按category分组,再对每个分组内的元素按value降序计算排名,这样能保证同类别内的排名逻辑准确,同时不干扰全局排名的计算。以下是具体实现:
步骤1:按Category分组
先把原数组按category拆分成多个子数组,方便单独处理每个类别的排名:
const groupedByCategory = {}; array.forEach(item => { if (!groupedByCategory[item.category]) { groupedByCategory[item.category] = []; } groupedByCategory[item.category].push(item); });
步骤2:为每个分组计算Rank
对每个分组内的元素,先按value降序排序,再遍历计算排名(相同值保留同一排名):
Object.values(groupedByCategory).forEach(group => { // 复制分组并排序,避免修改原数组的顺序 const sortedGroup = [...group].sort((a, b) => b.value - a.value); let currentRank = 1; sortedGroup.forEach((item, index) => { // 只有当前值比前一个小时,才更新排名 if (index > 0 && item.value < sortedGroup[index - 1].value) { currentRank = index + 1; } // 给原数组元素添加rank字段(因为是引用,原数组会同步更新) item.rank = currentRank; }); });
步骤3:保留你的Overall_Rank计算逻辑
你之前的全局排名代码可以直接复用,注意如果不想修改原数组的顺序,可以先复制数组再排序:
// 复制数组并按value降序排序,不改动原数组 const sortedForOverall = [...array].sort((a, b) => b.value - a.value); let overallRank = 1; sortedForOverall.forEach((item, index) => { if (index > 0 && item.value < sortedForOverall[index - 1].value) { overallRank++; } item.overall_rank = overallRank; });
完整代码示例
把以上步骤整合起来,运行后就能得到你想要的结果:
const array = [ {country: "Germany", category: "A", value: 300}, {country: "Brazil", category: "A", value: 200}, {country: "Canada", category: "A", value: 200}, {country: "Germany", category: "B", value: 100}, {country: "Brazil", category: "B", value: 400}, {country: "Canada", category: "B", value: 500}, ]; // 按category分组 const groupedByCategory = {}; array.forEach(item => { if (!groupedByCategory[item.category]) { groupedByCategory[item.category] = []; } groupedByCategory[item.category].push(item); }); // 计算每个分组的rank Object.values(groupedByCategory).forEach(group => { const sortedGroup = [...group].sort((a, b) => b.value - a.value); let currentRank = 1; sortedGroup.forEach((item, index) => { if (index > 0 && item.value < sortedGroup[index - 1].value) { currentRank = index + 1; } item.rank = currentRank; }); }); // 计算overall_rank const sortedForOverall = [...array].sort((a, b) => b.value - a.value); let overallRank = 1; sortedForOverall.forEach((item, index) => { if (index > 0 && item.value < sortedForOverall[index - 1].value) { overallRank++; } item.overall_rank = overallRank; }); console.log(array);
方法优势
- 分组处理逻辑清晰,不会因为全局排序打乱类别内的排名计算
- 相同
value的元素会得到相同的排名,完全符合预期结果 - 不修改原数组的原始顺序(如果需要保留的话),适合处理大型数组
内容的提问来源于stack exchange,提问作者console.log
相关产品推荐
相关产品推荐

