简体   繁体   中英

How to find inside an array of objects the object that holds the highest value?

I have an array that holds several objects named student, each object student has several properties, one of which is an array named grades.

I need to create a function that loops through the student's array and finds which student object has the highest grade inside its grades array.

At the moment I am able to find the highest score, but was not able to understand how to trace back to which student it belongs to.

Here is a snippet of how the function looks like:

function bestStudent() {
    var bestGrade = 0;
    var student;
    for(i=0; i < studentArr.length; i++) {
        var student = studentArr[i];
        grades = student.grades;
        for(g = 0; g <grades.length; g++){
            if(grades[g] > bestGrade) {
                bestGrade = grades[g];      
            }
        }

    }    
}

The general idea is the following: you can first map your array of students with their grades to an array of students and their highest grade in order to make it convenient to work with and avoid multiple find-max-grade calculations, and then find the largest of students' highest grade.

Just an example:

 var students = [ { name: "Student 1", grades: [ 65, 61, 67, 70 ] }, { name: "Student 2", grades: [ 50, 51, 53, 90 ] }, { name: "Student 3", grades: [ 0, 20, 40, 60 ] } ]; var highestGrades = students.map(function(stud, ind) { // return a student's name and his highest grade (1) return { name: stud.name, highestGrade: Math.max.apply(Math, stud.grades) // get a student's highest grade }; // or return index and use it to access original value: (2) // return { // index: ind, // highestGrade: Math.max.apply(Math, stud.grades) // }; // or return the whole student: (3) // return { // student: stud, // highestGrade: Math.max.apply(Math, stud.grades) // }; // or just add 'highestGrade' property to object without modifying // if it's ok for you to have intermediate properties in your object: (4) // stud.highestGrade = Math.max.apply(Math, stud.grades); // return stud; }); // this can be done in O(n), not in O(N * logN) if required: var bestStudent = highestGrades.sort(function(a, b) { return b.highestGrade - a.highestGrade; })[0]; // sort by highest grade desc and return the first (the best) one // Here we have bestStudent with his name according to map function: console.log(bestStudent.name + " has the highest score of " + bestStudent.highestGrade); // (1) // console.log(students[bestStudent.index].name + " has the highest score of " + bestStudent.highestGrade); // (2) // console.log(bestStudent.student.name + " has the highest score of " + bestStudent.highestGrade); // (3) // console.log(bestStudent.name + " has the highest score of " + bestStudent.highestGrade); // (4) 

You can rewrite this code so that it returns the whole student as the result, or its index, or its specific properties. You can also just add highestGrade property to original object if it's ok for your objects to have an additional intermediate property. It is up to you, the idea doesn't change :)

This code is pretty long, but it is readable and makes the idea of algorithm clear, it is very important since you are a beginner.
If you and your team are fans of shorter but more complex code, then you can easily rewrite it.
Just something like this:

 var students = [ { name: "Student 1", grades: [ 65, 61, 67, 70 ] }, { name: "Student 2", grades: [ 50, 51, 53, 90 ] }, { name: "Student 3", grades: [ 0, 20, 40, 60 ] } ]; var bestStudent = students.map(function(stud) { stud.highestGrade = Math.max.apply(Math, stud.grades); return stud; }).sort(function(a, b) { return b.highestGrade - a.highestGrade; })[0]; console.log(bestStudent); 

By using the same function, you can store the position or the appropriate field

 function bestStudent() {
       var bestStudent = {};
       bestStudent.bestGrade = 0;
       var student;
       for(i=0; i < studentArr.length; i++) {
          var student = studentArr[i];
          grades = student.grades;
          for(g = 0; g <grades.length; g++){
             if(grades[g] > bestStudent.bestGrade) {
                bestStudent.bestGrade = grades[g];
                bestStudent.name =  studentArr[i].name;    
             }
          }

       } 

       return bestStudent;
    }

  var students = [ { name: "Student 1", grades: [ 90, 98, 80 ], getMyHighest: function(){ return Math.max.apply( Math, this.grades ); } }, { name: "Student 2", grades: [ 75, 85, 79 ], getMyHighest: function(){ return Math.max.apply( Math, this.grades ); } } , { name: "Student 3", grades: [ 75, 85, 99 ], getMyHighest: function(){ return Math.max.apply( Math, this.grades ); } } ]; var student = students.sort(function(f, l) { return l.getMyHighest() - f.getMyHighest(); })[0]; console.log(student); 

use lodash.js to make thing easy :)

var students=[{Grades:[1,2,3]},{Grades:[5,4,3]},{Grades:[7,77,4]}];


var studentWithBestGrade=_.map(students,function(student,position){

                return [position,_.max(student.Grades)];

});


console.log(studentWithBestGrade) //[[0,3],[1,5],[2,77]] 

find it JSFIDDLE

My solution would be using reduce in JS

Only get one student:

var bestStudent = students.reduce(function(a, student){
    return Math.max.apply(null, student.grades) >  
           Math.max.apply(null, a.grades) ? 
           student : a;}, students[0]);

console.log('Best student is: ' + bestStudent.name + ' with score: ' 
            + Math.max.apply(null, bestStudent.grades));

Example: https://jsfiddle.net/ahx8jh5g/

In case, you want to get all students which have best grade, let's store it in an array:

var bestStudents = students.reduce(function(a, student){
    var maxGradeStu = Math.max.apply(null, student.grades),
        maxGradeCur = a.length > 0 ? Math.max.apply(null, a[0].grades) : 0;

        if (maxGradeStu === maxGradeCur) {
            return a.concat(student);
        }
        return maxGradeStu > maxGradeCur ? [student] : a;
}, [])
bestStudents.forEach( bestStudent => console.log('Best student is: ' bestStudent.name + ' with score: ' 
            + Math.max.apply(null, bestStudent.grades)));

For more detail, you can see reduce here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce

You could use an array for the students with the best grade, if you have more than one.

Then check if the maxGrade is the same as the bestGrade , then push the actual student to the result set and countinue the for loop.

If maxGrade is greater than bestGrade , store the value an put the actual student in a new array.

 function bestStudents(studentArr) { var bestGrade = 0, bestStudents = [], i, maxGrade; for (i = 0; i < studentArr.length; i++) { maxGrade = Math.max.apply(null, studentArr[i].grades); if (maxGrade === bestGrade) { bestStudents.push(studentArr[i]); continue; } if (maxGrade > bestGrade) { bestGrade = maxGrade; bestStudents = [studentArr[i]]; } } return bestStudents; } var students = [{ name: "Student 1", grades: [90, 98, 99] }, { name: "Student 2", grades: [75, 85, 79] }, { name: "Student 3", grades: [75, 85, 99] }]; console.log(bestStudents(students)); 
 .as-console-wrapper { max-height: 100% !important; top: 0; } 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM