微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

通过对象属性对象数组获得平均值的最有效方法

如何解决通过对象属性对象数组获得平均值的最有效方法

我为每个用户提供了多门课程的用户评分。我需要获得每个课程代码的平均用户评分。

获得这些平均值的最有效方法是什么?可以在以下两种格式中的任何一种中找到数据(尽管最好第二种格式更好)。

我想对数组进行排序,然后聚合值,直到找到不同的课程代码,但我对数组函数不是很擅长,我想知道是否有使用哈希图更快的方法来做到这一点,{{1} }、.mapsets。请帮助我找到一个有效的解决方案,因为有很多用户,我希望它尽可能快,以便网站加载速度更快。

reduce
[
    [
        {courseCode: "SYD393",rating: 3},{rating: 3,courseCode: "STA244"},{courseCode: "STA255",rating: 5},{rating: 5,courseCode: "CSE201"},{courseCode: "CSE255",rating: 4},{rating: 2,courseCode: "CSE202"},{courseCode: "ASD323",],[
        {courseCode: "ASD323",{courseCode: "SYD393",rating: 1},//...more arrays for each user
];

解决方法

看起来这与您自己发布的答案相似,只是我将 Map 的平均分成了自己的步骤。

const data = [[{ SYD393: 3 },{ STA244: 4 },{ STA255: 5 },{ CSE255: 4 },{ ASD323: 5 },],[{ ASD323: 5 },{ SYD393: 1 },];
const avg = a => a.reduce((a,b) => a + b,0) / a.length,sums = data.flat().reduce((a,o) => {
    const [[c,r]] = Object.entries(o);
    a.set(c,(a.get(c) ?? []).concat(r));
    return a;
  },new Map),avgs = new Map([...sums.entries()].map(([c,rs]) => [c,avg(rs)])),res = data.map(us => us.map(o => {
    const [k] = Object.keys(o); return { [k]: avgs.get(k) }
  }));

console.log(res);
.as-console-wrapper { max-height: 100% !important; top: 0; }

尽管使用您的第一个数据形状更简单,因为无需纠缠 Object.entries/keys

const data = [[{ courseCode: "SYD393",rating: 3 },{ rating: 3,courseCode: "STA244" },{ courseCode: "STA255",rating: 5 },{ rating: 5,courseCode: "CSE201" },{ courseCode: "CSE255",rating: 4 },{ rating: 2,courseCode: "CSE202" },{ courseCode: "ASD323",[{ courseCode: "ASD323",{ courseCode: "SYD393",rating: 1 },{ courseCode: c,rating: r }) =>
    (a.set(c,(a.get(c) ?? []).concat(r)),a),res = data.map(us => us.map(({ courseCode: c }) => ({ courseCode: c,rating: avgs.get(c) })));

console.log(res);
.as-console-wrapper { max-height: 100% !important; top: 0; }

,

这应该会让你得到最终结果。它将每组数组映射到一个累加评分的reduce,然后通过另一个map/reduce组合获得最终输出。

let data = [
    [
        {courseCode: "SYD393",rating: 3},{rating: 3,courseCode: "STA244"},{courseCode: "STA244",rating: 4},{courseCode: "STA255",rating: 5},{rating: 1,courseCode: "SYD393"},{rating: 5,courseCode: "CSE201"},{courseCode: "CSE255",{rating: 2,courseCode: "CSE202"},{courseCode: "ASD323",[
        {rating: 3,{courseCode: "SYD393",rating: 1},];

let newdata = data.map(e => e.reduce((b,a) => {
  let i = b.findIndex(e => e.courseCode === a.courseCode);
  if (i > 0) b[i].ratings.push(a.rating);
  else b.push({ ...a,ratings: [a.rating] });
  return b;
},[]).map(e => ({ [e.courseCode]: e.ratings.reduce((b,a) => b + a,0) / e.ratings.length
})))

console.log(newdata)

,

更新: 我的一个朋友提出了以下建议:

function averageRatings(data)
{
   let step1 = data.flat()
   let step2 = step1.reduce((c,i) => { if (!c.hasOwnProperty(i.courseCode)) {c[i.courseCode] = []} c[i.courseCode].push(i.rating); return c},{})
   let step3 = Object.entries(step2).map(([k,i]) => { return { courseCode: k,avg: i.reduce((c,v) => c+v) / i.length }})
}

它应该能够在 O(n) 时间内创建我正在寻找的内容,因为它使用了哈希表,但我不确定,因为它确实做了许多部门(昂贵的操作)和计算机 i.length 多次。

>

更简洁的版本:

function averageRatings(data)
{
    return Object.entries(data.flat().reduce((c,{})).map(([k,v) => c+v) / i.length }})
}

我在朋友的帮助下能想出的最快版本:

  function averageArray(array) {
    let sum = 0;
    let i = 0;
    for (; array[i]; i++) {
      sum += array[i];
    }
    return sum / i;
  }
function getAverageRatings(data){
  return Object.entries(
    data
      .flat()
      .reduce((c,i) => {
        if (!c.hasOwnProperty(i.courseCode)) {
          c[i.courseCode] = [];
        }
        c[i.courseCode].push(i.rating);
        return c;
      },{})
  ).map(([k,i]) => {
    return { courseCode: k,avg: averageArray(i) };
  });
}

通过删除 .length().reduce() 操作/函数回调进一步优化代码

,

这可能不会像您想象的那样影响您的网站,但这是我的建议: 如果您只担心平均评分,那么完美的方法是在内部使用 Array#reduce 和 Array#map:

const myUsers = [
    [
        {courseCode: "SYD393",];


// The map function iterates throught myUsers array
// The reduce function will summ all the evaluation ratings
// the user.length divisor will transform the sum into an avarage
const usersAverageEval = myUsers.map(user => (
    (user.reduce((accumulator,line) => (accumulator + line.rating),0))/user.length
))

这会产生更具可读性的代码,但不是最具执行力的方式。如果您只关心性能,我会使用您已经在使用的基本 for 循环,因为它们比这个 Array 方法快三到四倍。您可以在此处验证我所说的内容并了解更多信息:https://leanylabs.com/blog/js-forEach-map-reduce-vs-for-for_of/

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。