1

I have an array that consist of feedback objects. Each object is a user feedback left for a product:

Array [ {…}, {…} ]
0: Object { id: "1223", quality: 3, material: 4, … }
1: Object { id: "7342", quality: 3, material: 5, … }
...

Users can leave feedback for each category quality, material, ... out of 5.

I want to use the weighted average so on my site, I can show for example:

quality: 3
material: 4

This is weighted average calculated by this formula:

quality: (5*0 + 4*0 + 3*2 + 2*0 + 1*0) / (2) = 3
material: (5*1 + 4*0 + 3*1 + 2*0 + 1*0) / (2) = 4

I want to add this my js project, so I loop through all feedback:

const total = []
const feedback = [{
    id: "1223",
    quality: 3,
    material: 4,
  },
  {
    id: "7342",
    quality: 3,
    material: 5,
  }
];
feedback.forEach(function(arrayItem) {
  const score = arrayItem.quality
  total.push(score)
})
console.log(total.reduce((partialSum, a) => partialSum + a, 0))

I am confused about how to do the calculation for each star, for example to get number of 1s, 2s, 3s, 4s, and 5 starts. How can I modify my code to return the rating result?

Rain Man
  • 1,163
  • 2
  • 16
  • 49
  • If you only want the weighted average and not the number of products in each star rating, then the total - which you have already calculated - is all you need. – Fractalism Jan 23 '23 at 19:42
  • I want the weighted average for each category, quality for example should be 3 – Rain Man Jan 23 '23 at 19:44

3 Answers3

2

You could collect all sums in an object and calculate the aveage on the fly.

If you need an array, take only the values.

const
    feedback = [{ id: "1223", quality: 3, material: 4 }, { id: "7342", quality: 3, material: 5 }],
    types = ['quality', 'material'],
    result = feedback.reduce((r, o) => {
        types.forEach(type => {
            r[type] ??= { type, total: 0, count: 0 };
            r[type].total += o[type];
            r[type].avarage = r[type].total / ++r[type].count;
        });
        return r;
    }, {});

console.log(result);
console.log(Object.values(result));
.as-console-wrapper { max-height: 100% !important; top: 0; }
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
0

By changing the total variable from an array to an integer, we can add up the values first, and then divide them by the number of items in feedback to obtain the average rating.

const feedback = [{
    id: "1223",
    quality: 3,
    material: 4,
  },
  {
    id: "7342",
    quality: 3,
    material: 5,
  }
];

let totalQuality = 0;
let totalMaterial = 0;
feedback.forEach(function(arrayItem) {
    totalQuality += arrayItem.quality;
    totalMaterial += arrayItem.material;
})
let avgQuality = totalQuality / feedback.length;
let avgMaterial = totalMaterial / feedback.length;
console.log(avgQuality);
console.log(avgMaterial);
Fractalism
  • 1,231
  • 3
  • 12
0

If every feedback has a quality and material rating the following code should work.

Since every feedback has a rating you can just use the .length of that Array to determine the total count of feedback. Then it's just a matter of adding them up since.
(5*2 + 4*0 + 3*0 + 2*2 + 1*0) / 4 = 5/4 + 5/4 + 2/4 + 2/4

    const feedbacks = [
        {
            id: "1223",
            quality: 3,
            material: 4,
        },
        {
            id: "7342",
            quality: 3,
            material: 5,
        },
        {
            id: "7382",
            quality: 1,
            material: 2,
        },
    ];

    const feedbackCount = feedbacks.length;
    const weightedAverageFeedback = feedbacks.reduce((acc, feedback) => {
        acc.quality += feedback.quality / feedbackCount;
        acc.material += feedback.material / feedbackCount;
        return acc;
    }, { quality: 0, material: 0 });

    console.log("weighted average quality feedback", weightedAverageFeedback.quality);
    console.log("weighted average material feedback", weightedAverageFeedback.material);

    console.log("quality average feedback rounded up", Math.ceil(weightedAverageFeedback.quality / 0.5) * 0.5);
    console.log("material average feedback rouned up", Math.ceil(weightedAverageFeedback.material / 0.5) * 0.5);
tomdraws
  • 16
  • 3