Javascript function returning 'undefined'

2.5k Views Asked by At

I've written a a function which takes score as parameter and should return the letter grade. There are some conditions to be followed while writing the code. ie: return 'A' if 25 < score <= 30 return 'B' if 20 < score <= 25 and so on. So I wanted to do this by omitting a whole lot of if-else's. As I'm new to javascript this is all I could come up with:

// This function takes Nested arrays and a single number, 
// which checks its availability in 
// the inside array and then return the index of the array
function my_index(arr, score) {
    for (const [index, elem] of arr.entries()) {
        if (elem.includes(score)) {
            return index;
        }
        
    }
}

// function to get letter grade
function getGrade(score) {
    let grade;
    var gradeDict = {
        'A': [26, 27, 28, 29, 30],
        'B': [21, 22, 23, 24, 25],
        'C': [16, 17, 18, 19, 20],
        'D': [11, 12, 13, 14, 15],
        'E': [6, 7, 8, 9, 10],
        'F': [0, 1, 2, 3, 4, 5] 
    }
    var keys = Object.keys(gradeDict);
    var values = [Object.values(gradeDict)]
    grade = keys[my_index(values, score)]
        
    return grade;
}

The first function works fine. It returns the index of nested array. But the main function getGrade happens to return 'Undefined'. Can't think of a better solution than this to reduce a bunch of ugly if-elses.

var question = {
    '1st': 'Can anybody help me get this done?',
    '2nd': 'Is there any better way to do this?'
}
3

There are 3 best solutions below

4
DecPK On BEST ANSWER

Remove the outer [] array of the Object.values. Object.values already returns values in array.

from

var values = [Object.values(gradeDict)];

to

var values = Object.values(gradeDict);

working example:

function my_index(arr, score) {
  for (const [index, elem] of arr.entries()) {
    if (elem.includes(score)) {
      return index;
    }
  }
}

function getGrade(score) {
  let grade;
  var gradeDict = {
    A: [26, 27, 28, 29, 30],
    B: [21, 22, 23, 24, 25],
    C: [16, 17, 18, 19, 20],
    D: [11, 12, 13, 14, 15],
    E: [6, 7, 8, 9, 10],
    F: [0, 1, 2, 3, 4, 5],
  };
  var keys = Object.keys(gradeDict);
  var values = Object.values(gradeDict);
  grade = keys[my_index(values, score)];

  return grade;
}

console.log(getGrade(5));
console.log(getGrade(25));

Alternate solution

function getGrade(score) {
  let grade;
  var gradeDict = {
    A: [26, 27, 28, 29, 30],
    B: [21, 22, 23, 24, 25],
    C: [16, 17, 18, 19, 20],
    D: [11, 12, 13, 14, 15],
    E: [6, 7, 8, 9, 10],
    F: [0, 1, 2, 3, 4, 5],
  };

  for (let key in gradeDict) {
    if (gradeDict[key].includes(score)) return key;
  }

  return "Not found";
}

console.log(getGrade(5));
console.log(getGrade(25));

1
meriton On

Is there a better way to write this?

I'd do:

function getLetterGrade(score) {
  return ['F', 'F', 'E', 'D', 'C', 'B', 'A'][Math.ceil(score / 5)];
}

(F occurs twice because more scores map to F than to other grades)

It may be a bit cryptic, but is easier to tune should the possible score ever change.

1
jarmod On

I like the ceil solution proposed earlier, but here is another general solution in case it's helpful:

function grade(score) {
  if (score < 0 || score > 30) throw RangeError(`Score ${score} out of range`);

  for (let ii = 5; ii >= 0; ii--) {
    if (score > 5*ii) return String.fromCharCode(70 - ii);
  }

  return 'F';
}

console.log(0, '=>', grade(0))   // F
console.log(4, '=>', grade(4))   // F
console.log(6, '=>', grade(6))   // E
console.log(10, '=>', grade(10)) // E
console.log(27, '=>', grade(27)) // A
console.log(30, '=>', grade(30)) // A