如何基于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为键,存储每个分组的总分和评分数量,之后再和景点数据匹配计算平均值。具体分两步走:
用reduce分组统计评分
把reduce的初始值设为一个空对象,遍历reviews的时候,对每个id对应的条目维护两个属性:totalScore(总分)和count(评分次数)。匹配景点数据计算平均值
遍历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




