I am trying to take the average of 3 grades for three student (stored in an array of arrays), and then run those averages through a function with an else if statement to check whether the average grades are each and A,B or C.
I would prefer not to have to make a separate function with an else if for each students average (so I would know how to scale this to more than 3 inputs), and I am not sure how I can index the averageGrades array in the function so that I can console.log each element (student) of the averageGrades array and have the else if statement evaluate that particular element (student).
I also tried making an averageGrade variable for each student so that the averageGrades array had single values and not a full equation but ran into the same problem.
var studentGrades = [
[80, 90, 94],
[80, 90, 94],
[80, 90, 94]
]
var studentAvgerages = [
(studentGrades[0][0] + studentGrades[0][1] + studentGrades[0][2]) / 3,
(studentGrades[1][0] + studentGrades[1][1] + studentGrades[1][2]) / 3,
(studentGrades[2][0] + studentGrades[2][1] + studentGrades[2][2]) / 3
]
for (var i = 0; i <= studentAvgerages.length; i++) {
function evalGrades(studentAvgerages[i]) {
if (studentAvgerages[i] >= 90) {
return "A"
} else if ((studentAvgerages[i] >= 80) && (studentAvgerages[i] < 90)) {
return "B"
} else if ((studentAvgerages[i] >= 70) && (studentAvgerages[i] < 80)) {
return "C"
} else {
return "Failed"
}
}
}
console.log(evalGrades(studentAvgerages[0]))
console.log(evalGrades(studentAvgerages[1]))
console.log(evalGrades(studentAvgerages[2]))
Thought I knew what you were looking for, less sure now, but hope this helps a little, somehow? As others have shown, there are some one liners to arrive at your average, if that's what you want.
var studentGrades = [
[80, 90, 94],
[80, 90, 94],
[80, 90, 94]
]
for(var i=0; i < studentGrades.length; i++){
var avg = 0;
for(var j=0; j < studentGrades[i].length; j++){
avg += studentGrades[i][j];
}
avg = avg/studentGrades[i].length;
switch(true){
case (avg >= 90):
console.log("A");
break;
case (avg >= 80):
console.log("B");
break;
case (avg >= 70):
console.log("C");
break;
case (avg >= 60):
console.log("D");
break;
default:
"Failed";
break;
}
}
I prefer switch...case for tasks like this a lot of times, but don't forget to take into account performance. On an array of 20,000 sets of 200 student grades, might be worth using if/else to maintain speed of page. See this answer for more details.
You could take an exit early approach fro getting the grade. No else parts are necessary bycause of the return statement.
For getting the average, you could take a dynamic approach with adding values and divide by the length of the array.
const
add = (a, b) => a + b,
getAverage = array => array.reduce(add, 0) / array.length,
evalGrades = grade => {
if (grade >= 90) return "A";
if (grade >= 80) return "B";
if (grade >= 70) return "C";
return "Failed";
},
studentGrades = [[80, 90, 94], [80, 70, 60], [76, 82, 91]],
studentAvgerages = studentGrades.map(getAverage);
console.log(...studentAvgerages);
console.log(...studentAvgerages.map(evalGrades));
If you are new at programming or javascript, practice some basic examples first and try to understand how the code should be structured in a way you can manage and reuse it. Basically functional programming at least.
From what I understood from your code, you need something that can dynamically calculate the grades of the students.
I have re rewritten the code hope that helps. Also, try to debug the code on your own so as to figure out how the code flows.
var studentGrades = [
[80, 90, 94],
[80, 90, 94],
[80, 90, 94]
]
function evalGrades(grades) {
var sum = 0;
for(var i =0; i<grades.length; i++){
sum = sum + grades[i];
}
var avg = sum/grades.length;
if (avg >= 90) {
return "A"
} else if ((avg >= 80) && (avg < 90)) {
return "B"
} else if ((avg >= 70) && (avg < 80)) {
return "C"
} else {
return "Failed"
}
}
for (var i = 0; i < studentGrades.length; i++) {
console.log(evalGrades(studentGrades[i]))
}
Try this. I hope I've been helpful.
var studentGrades = [
[80, 90, 94],
[80, 90, 94],
[80, 90, 94]
]
for (var i = 0; i < studentGrades.length; i++) {
var average = studentGrades[i].reduce((a, b) => a + b, 0) / studentGrades[i].length;
if (average >= 90) { var result = "A" }
else if ( average >= 80 && average < 90 ) { var result = "B" }
else if ( average >= 70 && average < 80 ) { var result = "C" }
else { var result = "Failed" }
console.log(result);
}
Related
If I supply a number to a function, how would I go about validating it against a range of numbers like this?
1-10 = A
11-20 = B
21-30 = C
...
I know I can do if statements to evaluate this, but I'm looking for something more elegant because the problem gets a lot more complex and I don't want a nasty web of ifs.
var letter = "";
function getLetter(num) {
if (num >= 1 && num <= 10) {
letter = "A";
} else if (num >= 11 && num <= 20) {
letter = "B";
}
// this eventually gets gross
}
Expected outcome of getLetter(14) would be "B", and getLetter(49) would be "E", etc. Case/switch is also off the table for similar reasons.
Any other ideas welcome.
Just a point about your code
function getLetter(num) {
if (num >= 1 && num <= 10) {
letter = "A";
} else if (num >= 11 && num <= 20) {
letter = "B";
}
// this eventually gets gross
}
this can be simplified to
function getLetter(num) {
if (num >= 1) {
if(num <= 10) {
letter = "A";
} else if (num <= 20) {
letter = "B";
}
// this eventually gets gross too
}
}
But:
If it's as simple as every letter represents a range of 10 values:
function getLetter(num) {
return String.fromCharCode(65 + Math.floor((num - 1) / 10));
}
console.log(getLetter(1));
console.log(getLetter(14));
console.log(getLetter(49));
or as suggested
function getLetter(num) {
const ret = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
return ret[Math.floor((num - 1) / 10)] || "+"; // greater than 260
}
console.log(getLetter(1));
console.log(getLetter(14));
console.log(getLetter(49));
console.log(getLetter(261));
function getLetter(number) {
let ranges = {
a: 10,
b: 20,
c: 30,
underflow: 0,
overflow: Infinity
}
return Object.entries(ranges)
.sort(([ka, va], [kb, vb]) => va - vb) // because object key sort order isn't guaranteed
// though it will be in the order as declared, but
// sorting makes sense
.find(([key, value]) => number <= value)[0];
}
console.log(getLetter(5))
console.log(getLetter(17))
console.log(getLetter(20))
console.log(getLetter(30))
console.log(getLetter(31))
console.log(getLetter(0))
If the ranges are contiguous, you only need one of the boundaries
Works alright if you want to put your ranges into an object, and then loop through that
function getLetter (number) {
let ranges = {
a: [1, 10],
b: [11, 20],
c: [21, 30],
d: [31, 36],
e: [37, 40]
}
return Object.keys(ranges).find((key) => {
let currRange = ranges[key];
if (number >= currRange[0] && number <= currRange[1]) {
return key;
}
});
}
console.log(getLetter(5))
console.log(getLetter(17))
console.log(getLetter(20))
console.log(getLetter(30))
console.log(getLetter(35))
console.log(getLetter(39))
As a recent assignment for my coding bootcamp, we've been asked to create a function that takes an array of numbers as an argument and outputs them to an array of letter grades. I am stuck!
I've tried re-working and refactoring my code, changing the placement of different parts of the program, looking through MDN...
let grades = []
function getLetterGrades(grades) {
let grade = grades.map
if (grade < 60) {
return "F";
} else if (grade < 70) {
return "D";
} else if (grade < 80) {
return "C";
} else if (grade < 90) {
return "B";
} else if (grade < 100) {
return "A";
}
console.log(grades);
}
getLetterGrades([95, 85, 71]);
The results will only output the numbers I've entered into the function call.
You are using .map() wrong. What you are doing is comparing the map method to a number. You are not executing anything.
function getLetterGrades(grades) {
return grades.map(function(grade) {
if (grade < 60) {
return "F";
} else if (grade < 70) {
return "D";
} else if (grade < 80) {
return "C";
} else if (grade < 90) {
return "B";
} else if (grade < 100) {
return "A";
}
});
}
var letters = getLetterGrades([95, 85, 71]);
console.log(letters)
Your main issue is this:
let grade = grades.map
You are not invoking the .map method with (), so instead grade is winding up holding a reference to the native map function. And, that function isn't a number, so none of your conditions become true, so you continue past the if statement and just log the array that you passed in.
Instead, you must invoke .map() and supply its required parameter (a function that will be called for each item in the source array). Your if statement should be the body of that function:
let grades = []
function getLetterGrades(grades) {
let letterGrades = grades.map(function(grade){
if (grade < 60) {
return "F";
} else if (grade < 70) {
return "D";
} else if (grade < 80) {
return "C";
} else if (grade < 90) {
return "B";
} else if (grade < 100) {
return "A";
}
});
console.log(letterGrades);
}
getLetterGrades([95, 85, 71]);
Look at this solution:
let grades = []
function getLetterGrades(grades) {
// add an array (grade) that will hold the output
let grade = []
// iterate over grades with forEach()
grades.forEach(item => {
// item will be equal 95 on the first iteration
// 85 on the second, and 71 on the third - these
// values come from the passed 'grades' parameter
if (item < 60) {
grade.push("F");
} else if (item < 70) {
grade.push("D");
} else if (item < 80) {
grade.push("C");
} else if (item < 90) {
grade.push("B");
} else if (item < 100) {
grade.push("A");
}
})
// console.log(grade) - NOT grades!
console.log(grade);
}
getLetterGrades([95, 85, 71]);
The problem was not with the method you chose - the problem was you didn't finish your function. Here's another solution with map():
let grades = []
function getLetterGrades(grades) {
let grade = grades.map(item => {
if (item < 60) {
return "F";
} else if (item < 70) {
return "D";
} else if (item < 80) {
return "C";
} else if (item < 90) {
return "B";
} else if (item < 100) {
return "A";
}
})
// console.log(grade) - NOT grades!
console.log(grade);
}
getLetterGrades([95, 85, 71]);
In this case the main difference between forEach() and map() is that map() returns a NEW array (that's why you return values in the function body), and forEach() doesn't (we had to create the array - grade- manually, and push values into this "hand-made" array).
Look below to see what would happen, if we used forEach() WITHOUT a manually created array:
// THIS IS NOT A GOOD SOLUTION!
// IT GIVES YOU THE ANSWER IN THIS SMALL EXAMPLE
// (so you see that it's possible)
// BUT IN ANY LARGER CODE THIS IS THE
// 100% SURE SOURCE OF ERRORS.
let grades = []
function getLetterGrades(grades) {
grades.forEach((item, index) => {
if (item < 60) {
grades[index] = "F";
} else if (item < 70) {
grades[index] = "D";
} else if (item < 80) {
grades[index] = "C";
} else if (item < 90) {
grades[index] = "B";
} else if (item < 100) {
grades[index] = "A";
}
})
// console.log(grades) - NOT grade!
console.log(grades);
}
getLetterGrades([95, 85, 71]);
(I used the second argument of forEach() - that's index) THIS IS NOT A GOOD SOLUTION! Why? We "destroyed" our original grades array by overwriting it in getLetterGrades() - DON'T DO THIS!
As stated on map() takes a function and runs it once on each object in the array. To be clear on how you're trying to use it:
function getLetterGrades(grade) {
if (grade < 60) {
return "F";
} else if (grade < 70) {
return "D";
} else if (grade < 80) {
return "C";
} else if (grade < 90) {
return "B";
} else if (grade < 100) {
return "A";
}
}
x = [95, 85, 71];
//=> [A, B, C]
x.map(getLetterGrades);
Functionally, this is what the other answers are doing, they just aren't naming the method.
Post edited to change link as comment pointed out better resource.
I created a simple calculator
johnRestBill = [124, 48, 268, 180, 42]; //dollar
function tipCal(){
for(var i = 0; i < johnRestBill.length; i++){
if (johnRestBill[i] < 50) {
console.log(johnRestBill[i] * .2);
} else if (johnRestBill[i] >= 50 && johnRestBill[i] <= 200){
console.log(johnRestBill[i] * .15);
} else {
console.log(johnRestBill[i] * .1);
}
}
}
return tipCal();
I got the result of each index of johnRestBill array and now I want to make an array with the result.
So I made var tips = [] and typed tips.push(tipCal()) but it is not working and I don't know why...
To create tips, it would be much more appropriate to use .map instead, and for that, you need a function that returns the calculated tip:
const johnRestBill = [124, 48, 268, 180, 42];
function tipCal(bill) {
if (bill < 50) return bill * .2;
else if (bill >= 50 && bill <= 200) return bill * .15;
else return bill * .1;
}
const tips = johnRestBill.map(tipCal);
console.log(tips);
You can use array map method and return the same logical conditions
var johnRestBill = [124, 48, 268, 180, 42]; //dollar
// map returns a new array
let arr = johnRestBill.map(function(item) {
if (item < 50) {
return item * .2;
} else if (item >= 50 && item <= 200) {
return item * .15;
} else {
return item * .1;
}
})
console.log(arr)
I am working on a function that is supposed to return the closest lower number to a target from a list of integers. (i.e [1,23,45,67,94,122], target = 96. should return 94). I have gone through my code multiple times trying to "catch the bug" that makes this function return "undefined" and I haven't been able to find out why... When I print out my variable through the process, they all match what I want but my returning value keeps on being Undefined. I am thinking My problem is in the two first conditionals but, I still can't tell why. Any clue?
This is my code:
function binarySearch(arr,target){
var midpoint = Math.floor(arr.length/2);
if (arr[midpoint] === target){
return arr[midpoint];
}
if (arr.length === 1){
return arr[0];
}
if (arr[midpoint] > target){
binarySearch(arr.slice(0,midpoint),target);
}else if (arr[midpoint] < target){
binarySearch(arr.slice(midpoint),target);
}
}
binarySearch([1,23,45,67,94,122],96); => expected return value = 94 // getting = Undefined. :/
So the original algorithm seems wrong, choosing the largest value less than your target, not the one numerically closest to it.
Here's another version somewhat inspired by a java version, but written for ES6 and recursive like the question's code.
function binarySearch(arr, target, lo = 0, hi = arr.length - 1) {
if (target < arr[lo]) {return arr[0]}
if (target > arr[hi]) {return arr[hi]}
const mid = Math.floor((hi + lo) / 2);
return hi - lo < 2
? (target - arr[lo]) < (arr[hi] - target) ? arr[lo] : arr[hi]
: target < arr[mid]
? binarySearch(arr, target, lo, mid)
: target > arr[mid]
? binarySearch(arr, target, mid, hi)
: arr[mid]
}
console.log(binarySearch([1, 23, 45, 67, 94, 122], 96)) //=> 94
console.log(binarySearch([1, 23, 45, 67, 94, 122], 47)) //=> 45
console.log(binarySearch([1, 23, 45, 67, 94, 122], 207)) //=> 122
console.log(binarySearch([1, 23, 45, 67, 94, 122], 0)) //=> 1
You need to add return statements when you perform the recursive call
function binarySearch(arr,target){
var midpoint = Math.floor(arr.length/2);
if (arr[midpoint] === target){
return arr[midpoint];
}
if (arr.length === 1){
return arr[0];
}
if (arr[midpoint] > target){
return binarySearch(arr.slice(0,midpoint),target);
}else if (arr[midpoint] < target){
return binarySearch(arr.slice(midpoint),target);
}
}
I don't think your algorithm will give correct results.
You need to first find the position where the element should be inserted.
Here is the stack overflow link:
O(log n) algorithm to find best insert position in sorted array
function binarySearch(arr,target, l, h){
var midpoint = Math.floor(l+h/2);
if (arr[midpoint] === target){
return midpoint;
}
if (l === h){
return l;
}
if (arr[midpoint] > target){
return binarySearch(arr,target, l,midpoint);
}else if (arr[midpoint] < target){
return binarySearch(arr, target, midpoint,h);
}
}
function binaryclosest(arr, i){
x= abs(target - arr[i])
y = arr[i+1] - target
z = target - arr[i-1]
if(x<y && x<z){
return arr[i]
}
else{
if(y<z)
return arr[i+1]
else
return arr[i-1]
}
}
i = binarySearch(arr, target, l, h)
value = binaryclosest(arr, i)
Then, you should subtract the i-1 and i+1 take a mod and then return whichever is lower
1. Create a function toLetterGrade that takes an array of percentages and returns an array of corresponding grade letters. For example:
toLetterGrade([90,80,55,85]); //returns ["A","A-","C","A"]
2. Create a function toGradePoints that takes an array of letter grades and returns a corresponding array of grades points. For example:
toGradePoints(["A","A-","C","A"]); //returns [4.0,3.7,2.0,4.0]
3. Create a function GPA that takes an array of percentages and returns the corresponding grade point average.
I'm trying to do number 1, and this is the code I have so far, but it only gives me the letter grade for the last number in the array. What am I doing wrong?
var arr
function toLetterGrade(arr) {
for (i = 0; i < arr.length; i++) {
if (arr[i] >= 85) {
textG = "A";
} else if (arr[i] >= 80) {
textG = "A-";
} else if (arr[i] >= 75) {
textG = "B+";
} else if (arr[i] >= 70) {
textG = "B";
} else if (arr[i] >= 65) {
textG = "B-";
} else if (arr[i] >= 60) {
textG = "C+";
} else if (arr[i] >= 55) {
textG = "C";
} else if (arr[i] >= 50) {
textG = "D";
} else {
textG = "F";
}
}
return textG;
}
document.write(toLetterGrade([90, 80, 70]))
Output is B.
You are overwriting your variable with every cycle of the loop, that's why you are getting only one - the last grade.
I suggest you to use an empty array variable to store results inside.
With every loop you will assign new grade to the textG variable and then push it into the result array. The textG variable gets reseted with every loop textG = '' so there's no risk to duplicate/overwrite results.
After all cycles of the for loop, the result array is returned.
function toLetterGrade(arr) {
var textG = '';
var result = [];
for (i = 0; i < arr.length; i++) {
textG = '';
if (arr[i] >= 85) {
textG = "A";
} else if (arr[i] >= 80) {
textG = "A-";
} else if (arr[i] >= 75) {
textG = "B+";
} else if (arr[i] >= 70) {
textG = "B";
} else if (arr[i] >= 65) {
textG = "B-";
} else if (arr[i] >= 60) {
textG = "C+";
} else if (arr[i] >= 55) {
textG = "C";
} else if (arr[i] >= 50) {
textG = "D";
} else {
textG = "F";
}
result.push(textG);
}
return result;
}
document.write(toLetterGrade([90, 80, 70]))
For the first part, you could use an object and iterate the keys for the wanted grade.
function getGrade(p) {
var grade = 'F';
Object.keys(grades).some(function (k) {
if (p >= grades[k]) {
grade = k;
return true;
}
});
return grade
}
var grades = { A: 85, 'A-': 80, B: 70, 'B-': 65, 'C+': 60, C: 55, D: 50, F: '' }
console.log([90, 80, 55, 85].map(getGrade));
.as-console-wrapper { max-height: 100% !important; top: 0; }
You're assigning the grade to a variable and then overwriting it with each iteration.
try textG.push('A') instead
You are overwriting your return value with each iteration.
Try creating an array, and adding the solution onto the array.
var solutionArr = [];
solutionArr.push("A");
jsfiddle
I make this simple code to check letter grade from a numerical
const letterGrade = (n) => {
let resultGrade = "";
if (n >= 90) {
resultGrade = "A";
} else if (n >= 80 || n > 89) {
resultGrade = "B";
} else if (n >= 70 || n > 79) {
resultGrade = "C";
} else if (n >= 60 || n > 69) {
resultGrade = "D";
} else if (n < 59) {
resultGrade = "E";
} else {
alert("Input your grade first");
}
return `Your grade is ${resultGrade}`;
};
console.log(letterGrade(75));