What is the best way to calculate the average grade for each student in an array that contains objects with exam submission data?

Imagine having a collection of objects that hold details about exams submitted over a period. Here is the structure:

[
    { name: 'Freddy', grade: 10, date: '20/07/2022' },
    { name: 'Jose', grade: 8, date:'20/07/2022' },
    { name: 'Freddy, grade: 8', date: '25/07/2022' },
    { name: 'Daniel', grade: 5, date: '21/07/2022' },
    { name: 'Jose', grade: 5 }, date: '22/07/22',
  ]

The goal is to disregard the dates and compute the average grade for each student, resulting in a simple array like this:

[9, 6.5, 5]

In addition, if there's a need to reorder the array to match the sequence Freddy -> Jose -> Daniel, how can that be achieved?

While it may seem unusual, this specific order is necessary for later use as a dataset in Chart.js.

Answer №1

In order to achieve this:

  • I opted to utilize the `reduce` method to construct a dictionary containing the sum of grades and grade count for each student.

    • Choosing a dictionary was strategic as it facilitates easy navigation while `reduce` processes through the array.
  • Subsequently, I employed `Object.keys()` to extract an array of keys from the dictionary and then used `map` to convert this array into objects representing each student's average grade.

    • This approach was selected based on the notion that the resulting output could prove beneficial. While it may have been more straightforward to iterate over the dictionary directly and transform it into a collection of average values, I found this method preferable.
  • We proceeded to use `map` to isolate and retrieve only the average grades from the array of objects.

const students = [
  { name: 'Freddy', grade: 10, date: '20/07/2022' },
  { name: 'Jose', grade: 8, date:'20/07/2022' },
  { name: 'Freddy', grade: 8, date: '25/07/2022' },
  { name: 'Daniel', grade: 5, date: '21/07/2022' },
  { name: 'Jose', grade: 5 , date: '22/07/22'}
]

const grouped = students.reduce(
  (output, student) => {
    const name = student.name
    if (output[name]) {
      output[name].gradeTotal += student.grade;
      output[name].count += 1;
    }
    else {
      output[name] = {
        gradeTotal: student.grade,
        count: 1
      }
    }
   return output
  }, {})

console.log('Grouped by student: ', grouped)

const studentAverages = Object.keys(grouped).map(name => (
   {
    name,
    average: grouped[name].gradeTotal / grouped[name].count 
   }
  )
)

console.log('Student averages: ', studentAverages)

const justAverages = studentAverages.map(student => student.average)

console.log('Just averages:', justAverages)

Answer №2

It seems that you are looking for a solution to your problem.

  1. To tackle this issue, I created several variables such as sum, counter which help in counting the occurrence of each name, average and avgArr to store the averages.
  2. Next, I implemented nested loops where the outer loop extracts each object name and stores it in the name variable. The inner loop then searches through the array, calculates the average grade for each person with that name, and appends it to the avgArr array.
  3. In order to prevent duplicates, a checked property was added to each object. If an object is marked as true, it is skipped. If the property is missing, the object is processed, marked as true, and included in the calculations. This property can be removed if desired later on.

let arr =[
    { name: 'Freddy', grade: 10, date: '20/07/2022' },
    { name: 'Jose', grade: 8, date:'20/07/2022' },
    { name: 'Freddy', grade: 8, date: '25/07/2022' },
    { name: 'Daniel', grade: 5, date: '21/07/2022' },
    { name: 'Jose', grade: 5 , date: '22/07/22' }];
    let sum = 0;
    let counter = 0;
    let avg;
    const avgArr = [];
    for (const i of arr){
      let name = i.name;
      if (i.checked === true) {
        continue;
      }
      for (const j of arr){
        if (name === j.name) {
          j.checked = true;
          sum += j.grade;
          counter +=1;
        }
      }
      avg = sum / counter;                                                        
      avgArr.push(avg);
      sum = counter = 0;    
    }
     console.log(avgArr); // [9, 6.5, 5]

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

React/Express: Error 413 encountered when posting due to payload size exceeding limit and Bodyparser failing to handle it

I've exhausted all options but this issue seems unsolvable. I have scoured every single suggested fix on stackoverflow and gone through 3 pages of Google search results. Methods I've attempted Inserted extended: true/false in bodyParser.json U ...

Receiving the final outcome of a promise as a returned value

Seeking to deepen my comprehension of promises. In this code snippet, I am working on creating two promises that will return the numbers 19 and 23 respectively. However, when attempting to console log the value returned from the first promise, I encounte ...

Utilize strings as object keys in JavaScript

Let's say I have the following variables: var myKey = "This_is_my_key" var myObj = {"This_is_my_key" : true} What is the proper way to access myObj using the key myKey? ...

Trigger an alert after a separate function is completed with jQuery

On my page, I have a function that changes the color of an element. I want to trigger an alert once this action is complete using changecolor(). However, I am unable to modify the changecolor() function due to certain restrictions. Is there a way to dete ...

The output of PHP is not being captured by Ajax

I have a JavaScript code that calls a PHP script to retrieve a value, but it's not working as expected. Here is my JavaScript code: $.ajax({ type: 'GET', url: '/home/example.com/ftp/www/typo3conf/ext/quiz_rs/pi1', data ...

Angular UI Bootstrap Typeahead - Apply a class when the element is added to the document body

In my current project, I am utilizing angular bootstrap typeahead with multiple instances. Some of these instances are directly appended to the body using the "typeahead-append-to-body" option. Now, I have a specific instance where I need to customize the ...

When using React.js with Leaflet, ensure that the useEffect hook is only run on Mount when in the

I have encountered an issue where I need to ensure that the useEffect Hook in React runs only once. This is mainly because I am initializing a leaflet.js map that should not be initialized more than once. However, anytime I make changes to the component&a ...

Error encountered while trying to implement sleep function in script

Good evening. I've been attempting to implement the sleep function from the system-sleep library, but my script keeps crashing. This is the code snippet I'm working with: page.html <html lang="en"> <head> <meta charset= ...

Add an event listener to a specific class in order to control the visibility of its child elements by

Whenever I click on the "title text" link, the <ol> element refuses to hide, despite my efforts. After thoroughly reviewing the jQuery documentation and scouring Stack Overflow for answers related to .click(), .children(), .toggle(), and .hide(), I a ...

Guide on inserting a MUI datepicker string value into the object state

Currently, I am in the process of developing a todo-list application that includes fields for description, priority, and date. To capture the priority and description inputs, I utilize TextFields which trigger the {inputChanged} function. Within this funct ...

Vue Deep Watcher fails to activate when the data is altered

While the countdown timer is functioning properly, it seems that the deep watcher is not working as expected. Despite attempting to log the new value of seconds in the console, it does not display anything even though the countdown timer continues to funct ...

onmouseleave event stops triggering after blur event

I am facing an issue with a mouseleave event. Initially, when the page loads, the mouseleave event functions correctly. However, after clicking on the searchBar (click event), and then clicking outside of it (blur event), the mouseleave functionality stops ...

Utilizing the Ajax success callback to trigger a subsequent Ajax request as the loop iterates

I am currently working on a piece of javascript/jquery code that involves making ajax requests. The code snippet I have includes various variables and functions for handling external data sources and templates. var trigger = $('#loadTabl ...

Automatically updating the scope of the .filter() function

Is there a way to update the filter in the code below? .controller('MainCtrl', ["$rootScope", "$scope", function($rootScope, $scope) { $rootScope.number = 1; $scope.text = "foo|baz|bar" }]).filter("MyFormat", ["$rootScope", function($rootS ...

"Populate a textarea with the selected options from a multiple select dropdown

I am currently working on a form that contains several select boxes, some of which allow for multiple selections. I have successfully managed to pass the text value from each select box to a textarea. However, I am facing an issue where I am only able to p ...

What is the reason for the lack of user data being saved in studio3t?

I'm struggling to identify the issue in my app development process. I'm creating an application that collects user email and password, storing them in a database. The problem lies in the fact that while user passwords are successfully stored, the ...

What is the method for adding <option> tags to a <select> statement using a for loop?

Currently, I am facing a challenge in dynamically populating the <option> tags within a <select> menu. My approach involves using a for loop in JavaScript to cycle through the number of options and append them to the select tag. The part of th ...

Express.JS failing to save data to file when using NeDB

Currently, I am developing a bulk import feature for my personal password manager and I have encountered a problem. The issue arises when trying to import an array of passwords using the forEach() method to iterate through each one. After calling the inse ...

Obtaining an array element from mongoose at the corresponding index of the query

My Schema looks like this: const PublicationSchema = mongoose.Schema({ title: { type: String, required: true }, files:[{ contentType: String, data: Buffer, name: String }] }) I am attempting to re ...

Is there a way to automatically implode array chunks in PHP?

i have a chunked array: Array( [0] => Array ( [0] => "0" [1] => "1" [2] => "2" ) [1] => Array ( [3] => "3" [4] => "4" [5] => "5" ) [2] => Array ( [5] =& ...