Making the Grade

Rick Glascock
2 min readDec 12, 2020

Ranking and Ordering objects by Category

XinJiang, China — Rick Glascock

Here’s a challenge whose solution lets us use a variety of JavaScript’s features.

The Challenge: Given a group of numeric scores, between 0 and 100, compile the scores into a table that shows the percentage of the scores that fall in the various categories. Unrepresented categories should not be included in the results. The results should be sorted first by their percentage (to 2 decimal places) of the overall set of scores and next by the categories rank.

The categories and their respective score ranges:
Exceeding: 91–100
Meeting: 81–90
Passing: 71–80
Emerging: 61–70
Failing: 0–60

The sample set of scores [92, 83, 65, 63] would yield:
Emerging: 50.00%
Exceeding: 25.00%
Passing: 25.00%

‘Emerging’ tops the list with the highest percentage. ‘Exceeding’ comes before ‘Passing’ as its rank is higher.

Solution:

First we set up a lookup table, array that contains the category’s name, rank, range, and total number of instances as objects. Setting up this way allows us to easily adjust ranges if needed:

const categories = [
{ name: 'Failing', total: 0, rank: 1, min: 0, max: 60 },
{ name: 'Emerging', total: 0, rank: 2, min: 61, max: 70 },
{ name: 'Passing', total: 0, rank: 3, min: 71, max: 80 },
{ name: 'Meeting', total: 0, rank: 4, min: 81, max: 90 },
{ name: 'Exceeding', total: 0, rank: 5, min: 91, max: 100 },
];

Next we iterate through the list of scores finding the index of the category to which the score belongs to and adding to the total of that category. We also disregard any score outside the allowable range.

for (let i = 0; i < scores.length; i += 1) {
const idx = categories
.findIndex((category) => scores[i] >= category.min && scores[i] <= category.max);

if (idx !== -1) {
categories[idx].total += 1;
}
}

Because we will not include categories with no scores, we filter the results:

const finalCategories = categories.filter((cat) => cat.total > 0);

We will need to sort by two different criteria — by the percentage found and, if equal, by rank of the category. We set up a custom compare function to do this and then sort using the compare function:

function compare(a, b) {
if (a.total < b.total) return 1;
if (a.total > b.total) return -1;
if (a.rank > b.rank) return -1;
if (a.rank < b.rank) return 1;
return null;
}
finalCategories.sort((a, b) => compare(a, b));

We need the total number of scores that were within the allowable range to calculate the percentages. We can use the reduce function:

const finalTotal = finalCategories.reduce((acc, value) => acc + value.total, 0);

After setting up an empty array for our result, we iterate through the finalCategories building the output text:

const result = finalCategories.map((ele) => {
return `${ele.name}: ${((ele.total / finalTotal) * 100).toFixed(2)}%`;
});
return result;

That’s it!

--

--

Rick Glascock

After years of teaching music in Austin, Shanghai and Yangon, I’m making a career change to my other passion, software development.