How to sort letter grades in Javascript without a manual index
You could separate the grades and take an object for the postfix symbols.
const grades = ['B+', 'A', 'A-', 'A+', 'B', 'B-', 'C+', 'C', 'C-', 'D+', 'D', 'D-', 'F']
grades.sort((a, b) => {
const order = { '+': -1, '-': 1, undefined: 0 };
return a[0].localeCompare(b[0]) || order[a[1]] - order[b[1]];
});
console.log(...grades);
Actually simpler than you think:
const grades = ['B+', 'F', 'A-', 'A+', 'B', 'B-', 'C+', 'C', 'C-', 'D+', 'D', 'D-', 'A']
res = grades
.map(x => x + ',')
.sort()
.map(x => x.slice(0, -1))
console.log(res.join())
The "magic" here is that ,
is right between +
and -
in the ascii table, so A
becomes A,
and sorts between A+
and A-
.
As Nina suggested, you can also put the +,
thing right into the sort
callback:
const grades = ['B+', 'F', 'A-', 'A+', 'B', 'B-', 'C+', 'C', 'C-', 'D+', 'D', 'D-', 'A']
let cmp = (x, y) => (x > y) - (x < y);
res = grades.sort((x, y) => cmp(x + ',', y + ','))
console.log(...res)
where cmp
is the poor man's replacement for the <=>
operator
If you want to just stick to ASCII values:
const grades = ['B+', 'F', 'A-', 'A+', 'B', 'B-', 'C+', 'C', 'C-', 'D+', 'D', 'D-', 'A']
grades.sort((a, b) =>
a.charCodeAt(0) === b.charCodeAt(0) // If the letters are the same
? (a.charCodeAt(1) || 44) - (b.charCodeAt(1) || 44) // Just compare the postfix
: a.charCodeAt(0) - b.charCodeAt(0) // Otherwise compare the letters
);
console.log(...grades);
The ACII value of +
is 43 and the ASCII value of -
is 45, so we can use 44 (which is ,
) when there is no postfix.
Alternatively, using template literals:
const grades = ['B+', 'F', 'A-', 'A+', 'B', 'B-', 'C+', 'C', 'C-', 'D+', 'D', 'D-', 'A']
grades.sort((a, b) =>
a.charCodeAt(0) === b.charCodeAt(0)
? `${a},`.charCodeAt(1) - `${b},`.charCodeAt(1)
: a.charCodeAt(0) - b.charCodeAt(0)
);
console.log(...grades);