You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何基于API响应数据按ID分组计算评分平均值?

按ID分组计算评分平均值的实现方案

问题描述

我需要根据API响应中的ID计算对应对象的评分平均值,API返回数据如下:

const attractions = [ 
  {"id": 1,"name": "drive on avenue"}, 
  {"id": 2, "name": "diving"}, 
  {"id": 3,"name": "visiting mangroove"}, 
];
const reviews = [ 
  {"id": 1,"score": 1.5}, {"id": 2, "score": 2} , 
  {"id": 3,"score": 5.5}, {"id": 3,"score": 4}, 
  {"id": 2,"score": 3}, {"id": 1,"score": 3.5}, 
  {"id": 3,"score": 5}, {"id": 2,"score": 4} 
];

期望输出结果:

[{"name": "drive on avenue", "score": 2.5}, {"name": "diving", "score": 3}, {"name": "visiting mangroove", "score": 4.83} ]

我尝试用reduce方法实现,但它把所有评分累加在一起,没法按ID分组计算。请问该怎么实现按每个ID计算对应评分的平均值?


解决方案

其实reduce完全可以搞定分组计算,关键是让累加的对象以ID为键,存储每个分组的总分和评分数量,之后再和景点数据匹配计算平均值。具体分两步走:

  1. 用reduce分组统计评分
    reduce的初始值设为一个空对象,遍历reviews的时候,对每个id对应的条目维护两个属性:totalScore(总分)和count(评分次数)。

  2. 匹配景点数据计算平均值
    遍历attractions数组,根据id从统计好的对象中取出总分和次数,计算平均值后保留两位小数,最后整理成期望的格式。


完整代码示例

const attractions = [ 
  {"id": 1,"name": "drive on avenue"}, 
  {"id": 2, "name": "diving"}, 
  {"id": 3,"name": "visiting mangroove"}, 
];
const reviews = [ 
  {"id": 1,"score": 1.5}, {"id": 2, "score": 2} , 
  {"id": 3,"score": 5.5}, {"id": 3,"score": 4}, 
  {"id": 2,"score": 3}, {"id": 1,"score": 3.5}, 
  {"id": 3,"score": 5}, {"id": 2,"score": 4} 
];

// 第一步:分组统计每个id的总分和评分次数
const scoreStats = reviews.reduce((acc, review) => {
  const { id, score } = review;
  // 如果当前id还没在统计对象里,初始化总分和次数
  if (!acc[id]) {
    acc[id] = { totalScore: 0, count: 0 };
  }
  acc[id].totalScore += score;
  acc[id].count += 1;
  return acc;
}, {});

// 第二步:匹配景点数据,计算平均值并格式化
const result = attractions.map(attraction => {
  const { id, name } = attraction;
  const { totalScore, count } = scoreStats[id];
  // 计算平均值并保留两位小数
  const averageScore = parseFloat((totalScore / count).toFixed(2));
  return { name, score: averageScore };
});

console.log(result);
// 输出:[{"name": "drive on avenue", "score": 2.5}, {"name": "diving", "score": 3}, {"name": "visiting mangroove", "score": 4.83} ]

关键点说明

  • reduce的累加对象acc会变成类似{1: {totalScore:5, count:2}, 2: {...}, ...}的结构,完美实现按ID分组。
  • 使用toFixed(2)保留两位小数后,记得用parseFloat把字符串转回数字类型,避免结果是字符串格式。
  • 这种方法的时间复杂度是O(n + m)(n是reviews长度,m是attractions长度),效率很高。

内容的提问来源于stack exchange,提问作者Gift366

火山引擎 最新活动