I have the following multidimensional array of student objects:
var students = [
{name: "Jack", age: "NYN", attempts: 3, wrong: 2},
{name: "Phil", age: "NNNY", attempts: 4, wrong: 3},
{name: "Tom", age: "", attempts: 0, wrong: 0},
{name: "Lucy", age: "YYNY", attempts: 4, wrong: 1},
{name: "Ben", age: "NYNN", attempts: 4, wrong: 3},
{name: "Hardest", age: "NNN", attempts: 3, wrong: 3}
]
I'm trying to create an array 'peopleMostNeedingHelp' which only comprises of the students with the highest 'wrong' property values. So 'peopleMostNeedingHelp' should only contain the objects Phil, Ben and Hardest. The problem is, the way I've done it also includes the unwanted 'Jack' as he is the first comparison.
How can I create a function that only returns the people with the most wrong answers?
var s2 = "Jack:NYN,Phil:NNNY,Tom:,Lucy:YYNY,Ben:NYNN,Hardest:NNN";
var s2Arr = s2.split(','); // convert string to an array
var s2MdArr = s2Arr.map(function(e) {return e.split(':'); }); // convert to MD array
var totalWrongAnswers = 0;
for(i=0; i < s2Arr.length; i++) {
var attempts = s2MdArr[i][1].length;
var noWrong = (s2MdArr[i][1].match(/N/g) || []).length;
s2MdArr[i].push(attempts); // add to array[i][2]
s2MdArr[i].push(noWrong); // add to array[i][3]
totalWrongAnswers += noWrong; // update total wrong
}
var s2ArrObj = s2MdArr.map(function(e) { return {name: e[0], age: e[1], attempts: e[2], wrong: e[3]} }); // create objects in MD Array
var firstPerson = s2ArrObj[0]; // initialise so can make a comparison
var person = firstPerson;
var peopleMostNeedingHelp = [];
// update person to the person with the highest no. of wrong answers
function something() {
for (i = 0; i < s2ArrObj.length; i++) { // for each person
if (s2ArrObj[i].wrong >= person.wrong) { // problem = first instance always true
person = s2ArrObj[i]; // update person variable so can compare next person
peopleMostNeedingHelp.push(person);
}
}
}
something();
console.log(peopleMostNeedingHelp);
The most straight-forward algorithm to achieve your goal would be:
- Find the maximum value for
wrong
within students
array.
- Use
filter
to leave only the relevant students (with the property wrong
equals the maximum).
var students = [{name: "Jack", age: "NYN", attempts: 3, wrong: 2},{name: "Phil", age: "NNNY", attempts: 4, wrong: 3},{name: "Tom", age: "", attempts: 0, wrong: 0},{name: "Lucy", age: "YYNY", attempts: 4, wrong: 1},{name: "Ben", age: "NYNN", attempts: 4, wrong: 3},{name: "Hardest", age: "NNN", attempts: 3, wrong: 3}];
// Find the maximum 'wrong' value
let maxValue = 0;
for(let student of students) {
if(student.wrong > maxValue) {
maxValue = student.wrong;
}
}
// filter out the students with 'wrong' value different than the maximum
let onlyMax = students.filter(item => item.wrong == maxValue);
console.log(onlyMax);
Note all the algorithm does is iterating the array twice, resulting in run-time of O(2n) = O(n).
The more general solution allows one to find the items with maximum value of property
in an objects array:
var students = [{name: "Jack", age: "NYN", attempts: 3, wrong: 2},{name: "Phil", age: "NNNY", attempts: 4, wrong: 3},{name: "Tom", age: "", attempts: 0, wrong: 0},{name: "Lucy", age: "YYNY", attempts: 4, wrong: 1},{name: "Ben", age: "NYNN", attempts: 4, wrong: 3},{name: "Hardest", age: "NNN", attempts: 3, wrong: 3}];
function filterByMax(arr, property) {
// Find the maximum 'wrong' value
let maxValue = 0;
for(let item of arr) {
if(item[property] > maxValue) {
maxValue = item[property];
}
}
// filter out the students with 'wrong' value different than the maximum
return arr.filter(item => item[property] == maxValue);
}
console.log(filterByMax(students, 'wrong'));
You could reduce the array by checking the wrong
property.
var students = [{ name: "Jack", age: "NYN", attempts: 3, wrong: 2 }, { name: "Phil", age: "NNNY", attempts: 4, wrong: 3 }, { name: "Tom", age: "", attempts: 0, wrong: 0 }, { name: "Lucy", age: "YYNY", attempts: 4, wrong: 1 }, { name: "Ben", age: "NYNN", attempts: 4, wrong: 3 }, { name: "Hardest", age: "NNN", attempts: 3, wrong: 3 }],
topWrong = students.reduce((r, o) => {
if (!r || o.wrong > r[0].wrong) {
return [o];
}
if (o.wrong === r[0].wrong) {
r.push(o);
}
return r;
}, undefined);
console.log(topWrong);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You have to reset the peopleMostNeedingHelp
when a new student with a higher number of errors is discovered:
let mostNeedingHelp = [students[0]];
for(const student of students.slice(1)) {
if(student.errors === mostNeedingHelp[0].errors) {
mostNeedingHelp.push(student);
} else if(student.errors >= mostNeedingHelp[0].errors) {
mostNeedingHelp = [student]; // <<<<
}
}
This can be shortified with reduce:
const mostNeedingHelp = students.slice(1).reduce((arr, student) =>
arr[0].errors === student.errors ? arr.concat(student) : arr[0].errors < student.errors ? [student] : arr, [students[0]]);
Your code will also fail if the "wrong" property values are in ascending order like
var students = [
{name: "Jack", age: "NYN", attempts: 3, wrong: 2},
{name: "Phil", age: "NNNY", attempts: 4, wrong: 3},
{name: "Tom", age: "", attempts: 0, wrong: 0},
{name: "Lucy", age: "YYNY", attempts: 4, wrong: 1},
{name: "Ben", age: "NYNN", attempts: 4, wrong: 3},
{name: "Hardest", age: "NNN", attempts: 3, wrong: 3}
{name: "Mad", age: "NYN", attempts: 3, wrong: 5},
]
The result will include Jack, Phil, Ben, Hardest & Mad
You have to discard the previous results once you find new person with greater "wrong" value, see the snippet below...
var s2 = "Jack:NYN,Phil:NNNY,Tom:,Lucy:YYNY,Ben:NYNN,Hardest:NNN";
var s2Arr = s2.split(','); // convert string to an array
var s2MdArr = s2Arr.map(function(e) {return e.split(':'); }); // convert to MD array
var totalWrongAnswers = 0;
for(i=0; i < s2Arr.length; i++) {
var attempts = s2MdArr[i][1].length;
var noWrong = (s2MdArr[i][1].match(/N/g) || []).length;
s2MdArr[i].push(attempts); // add to array[i][2]
s2MdArr[i].push(noWrong); // add to array[i][3]
totalWrongAnswers += noWrong; // update total wrong
}
var s2ArrObj = s2MdArr.map(function(e) { return {name: e[0], age: e[1], attempts: e[2], wrong: e[3]} }); // create objects in MD Array
var firstPerson = s2ArrObj[0]; // initialise so can make a comparison
var person = firstPerson;
var peopleMostNeedingHelp = [];
// update person to the person with the highest no. of wrong answers
function something() {
for (i = 0; i < s2ArrObj.length; i++) {
// for each person
if (s2ArrObj[i].wrong > person.wrong) {
// discard previous results and create new list with single new person only
person = s2ArrObj[i];
// update person variable so can compare next person
peopleMostNeedingHelp = [person];
}
else if (s2ArrObj[i].wrong == person.wrong) {
// add the person to list
person = s2ArrObj[i];
// update person variable so can compare next person
peopleMostNeedingHelp.push(person);
}
}
}
something();
console.log(peopleMostNeedingHelp);