What is the best way to calculate the average of values from multiple objects sharing the same key in an array using JavaScript?

Consider an array with student profiles:

let profile = [
{student: "A", english: 80, maths: 80},
{student: "A", english: 70, maths: 60},
{student: "B", english: 50, maths: 50},
{student: "B", english: "--", maths: 60},
...
]

I am looking to extract two different sets of arrays based on the average scores.

  1. Average scores for each subject for each student (Expected output:)
[{student: "A", english: 75, maths: 70},
{student: "B", english: 50, maths: 55}]
  1. Average scores across all subjects for each student (Expected output:)
[{student: "A", average: 72.5},
{student: "B", average: 53.3}]

Could you help me with writing the code? I appreciate your assistance.

Answer №1

To analyze the students' scores effectively, one approach is to group the scores by subject and calculate the average for each subject. Then, you can further compute the overall average score for each student based on these subject averages.

const
    grades = [{ student: "A", english: 80, maths: 80 }, { student: "A", english: 70, maths: 60 }, { student: "B", english: 50, maths: 50 }, { student: "B", english: "--", maths: 60 }],
    subjectAverages = Object
        .values(grades.reduce((acc, { student, ...score }) => {
            acc[student] ??= { student };
            Object
                .entries(score)
                .forEach(([subject, value]) => {
                    if (isNaN(value)) return;
                    acc[student][subject] ??= { total: 0, count: 0 };
                    acc[student][subject].total += value;
                    acc[student][subject].count++;
                });
            return acc;
        }, {}))
        .map(({ student, ...score }) => ({
            student,
            ...Object.fromEntries(Object.entries(score).map(([subject, { total, count }]) => [subject, total / count]))
        })),
    studentAverages = subjectAverages.map(({ student, ...score }) => {
        const values = Object.values(score);
        return {
            student,
            averageScore: values.reduce((prev, curr) => prev + curr, 0) / values.length
        };
    });

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

Answer №2

I'm a bit skeptical of the average calculation for student B in the 2nd array...

Upon reviewing my code, I arrived at an average of 52.5 instead.

let profile = [
{student: "A", english: 80, maths: 80},
{student: "B", english: 50, maths: 50},
{student: "A", english: 70, maths: 60},
{student: "B", english: "--", maths: 60}
]


//sort by student
profile.sort((a, b) => a.student.localeCompare(b.student));


const studentsCount = profile.reduce((pre, cur, index) => {
    let find = profile.findIndex((e, _index) => _index > index && e.student === cur.student);
    if (find == -1) {
        return pre + 1;
    } else return pre;
}, 0);

//stage 1
let curProfile = profile[0], startIndex, endIndex, _profile = [], maths = 0, english = 0, noScoreMaths, noScoreEnglish;
for (let i = 0; i < studentsCount; i++) {
    startIndex = profile.findIndex(p => p.student === curProfile.student);
    endIndex = profile.findLastIndex(p => p.student === curProfile.student);
    noScoreMaths = 0, noScoreEnglish = 0;

    for (let j = startIndex; j <= endIndex; j++) {
        if (isNaN(parseInt(profile[j].maths))) noScoreMaths++;
        if (isNaN(parseInt(profile[j].english))) noScoreEnglish++;
        
        maths += isNaN(parseInt(profile[j].maths)) ? 0 : profile[j].maths;
        english += isNaN(parseInt(profile[j].english)) ? 0 : profile[j].english;
            
        if (j === endIndex) {
            maths = parseFloat((maths / (endIndex - startIndex + 1 - noScoreMaths)).toFixed(1));
            english = parseFloat((english / (endIndex - startIndex + 1 - noScoreEnglish)).toFixed(1));

            _profile.push({
                student: curProfile.student,
                maths,
                english
            });

            curProfile = profile[j + 1];
            maths = 0;
            english = 0;
            noScoreMaths = 0;
            noScoreEnglish = 0;
        }
    }
}

//stage 2
let __profile = [];

for (let i = 0; i < _profile.length; i++) {
    let avgScore = parseFloat(((_profile[i].maths + _profile[i].english) / 2).toFixed(1));
    __profile.push({ student: _profile[i].student, average: avgScore });
}

console.log(_profile);
console.log(__profile);

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Error: The variable fullName has not been declared

To start off, I need to develop a registration form that includes fields for full name, email, password, mobile number, and date of birth. Once the email validation is successfully completed and the submit button is clicked, the user should be redirected t ...

When there is only one value, the BehaviorSubject can be hit multiple times

Recently, I implemented BehaviourSubject in a shared service to retrieve the current value when clicking a button. Everything seems to be working fine, however, there are instances where the API call within the subscribe block of BehaviourSubject is being ...

Please provide links to both the image and text within a Rails 3.1 application

Hey there! I have a small piece of code and I'm wondering how to add a link to both the icon and text. I am calling an icon from a class. Check out my code below: <td class="cv-class_<%= index + 1 %>"> <a onClick="ad ...

What causes a Java InputMismatchException?

I need to handle an exception in my code in case the user inputs a string instead of an integer. The goal is to swap the positions of the largest and smallest indexes in the array. Can you assist me in correcting this issue? import java.util.Scanner; im ...

Utilizing various camera set-ups within Three.js

How can I smoothly switch between two different cameras in Three.js while transitioning from one to the other? Imagine a scene with a rock and a tree, each having its own dedicated camera setup. I'm looking for a way to seamlessly transition between ...

Looking to include a new item into an array with the help of AngularJS

Having just started with angularJS, I am facing difficulties in adding an object from a form to an array. When I click on "Add New Product", it triggers the "newItemModal". I enter the new product information but the submit button doesn't seem to work ...

We have successfully integrated the Wijemo event calendar with our Angular controller

I've been attempting to connect the wijeval to an array of events within an AngularJS Controller. Here's what I've attempted so far: View: <div ng-app="MyApp" ng-controller="MainController"> <wijevcal viewtype="week" eventsdat ...

Encountering a problem with the scope of child_process in Node

When utilizing the child_process module in Node.js with the fork method, I am able to send data to a specific file and receive a response. However, I am not logging this data to the console after receiving it from the execution process. The code in first. ...

Steps to designate a character depending on the frequency of its duplication within an array

I have a series of values in an array that I need to go through and assign incremental numerical values, starting from 1. If the same value appears more than once in the array, I want to append the original assigned number with the letter A, and then B, ac ...

Determine the total number of elements across various arrays with JavaScript

I'm currently in the process of calculating the total number of elements present in all columns under taskIds. I'm uncertain about the most effective method to achieve this as I am already mapping data in the return statement. My goal is to pass ...

What is the best way to achieve consistent alignment in Javascript?

I have been attempting to incorporate HTML code within JavaScript for alignment and styling. Despite searching on Google for 3 to 4 days, I have not found a suitable answer yet. What exactly am I looking for? Here is a snippet of my JavaScript code: funct ...

Encountering Issues with Formatting InnerHtml Text using RegEx

Technology: React.js I have been working on a custom function in JavaScript to highlight specific words within a code block. The function seems to be functioning correctly, but the highlighting isn't staying after the function is completed. Any ideas ...

What is the best way to calculate the number of div elements with a specific class that are contained within parent div elements with another specific class?

Is there a way to count the number of elements with the class '.child' in each container and then add a sentence containing that count inside each container? <div class='container'> <div class='child'></di ...

What is the simplest method for fetching and parsing JSON data with jQuery and JavaScript?

I'm having trouble making this code snippet work. I can't seem to figure it out. The objective is to retrieve and parse a JSON object in the simplest and easiest way possible. Here's the code snippet. <!DOCTYPE html> <html> &l ...

Utilizing numerous instances of setInterval

I've created a jsFiddle which can be found here: http://jsfiddle.net/dztGA/22/ Main Objective: My aim is to have two independent timers on the same page that can be stopped and restarted either by hovering or manually. The Issue: The problem illustr ...

What is the best way to randomly display an image from a JavaScript array within an HTML document?

I currently have this code in my HTML and JavaScript files, but I am having trouble with displaying images without using a URL in the JavaScript file. The images are located in my project folder. However, when I open the HTML file, the images do not appear ...

Display outcomes from various APIs using PHP and JavaScript

As someone new to PHP and JS, I am looking to create a script that can scan an API URL at The script should scan for values of userid from 0 to 100 and only display API results that match values found in a specific array. Results that do not align with th ...

Performing nested GridView calculations in an ASP.NET C# application by utilizing JavaScript/jQuery on the client side

I am facing a challenge with two gridviews inside another gridview where the footers display the total price and tax, while the gross total of all items in the inner gridviews should show in the footer of the main grid (GridView1). ...

Progress Circles on Canvas in FireFox

Currently, I am experimenting with this codepen demo that utilizes canvas to generate progress circles: The functionality functions perfectly in Chrome and Safari; however, it only displays black circles in FireFox. My knowledge of canvas is limited, so I ...

Using JQuery, you can toggle a newly created DIV element by linking it to `$(this)` instead of `$(this).closest()`

In the comment section, there is a link called "Reply" that triggers a pop-up comment box when clicked. However, I want the comment box to disappear if the "reply" button is clicked again, as it currently keeps opening more comment boxes. $('.replyli ...