Sorting numbers with Javascript

Wibecoding is everywhere nowadays. Apparently with wibecoding applications can be easily build. In order to understand or at least test the code, tests are needed. So a test driven development makes much sense in this scenario.

The author of a Linkedin post showed some code that apparently looks good and passes the test, while at the end, it does not. The real snippet was typescript code that declared the totals as an array of numbers.

function largestFirst(totals: Number[]): Number {
  return [...totals].sort().reverse();
}

If the function is fed with an array that does not contain numeric values, an error is thrown.

In plain Javascript the code looks like:

function largestFirst(totals) {
  return [...totals].sort().reverse();
}

However, this function can be fed with non numeric elements and will not fail. The totals could be even no array but this would cause an error of calling an undefined function sort().

Anyway, having a test like this:

console.log(largestFirst([200, 100, 300]));
[300, 200, 100]

looks pretty good. Test was passed.

Running the same code with:

console.log(largestFirst([900, 85, 1200]));
[900, 85, 1200]

returns obviously a wrong sequence.

So what is wrong with the code in the function?

The sort() does a string compare, even we provide integers here. Internally all elements are converted into a string hence the numbers are sorted alphabetically.

We need to provide our own comparing function that sort may take as an argument. The improved code looks like this now:

function largestFirst(totals) {
  return [...totals].sort((a, b) => Number(a) - Number(b)).reverse();
}

Basically the function for comparing two elements a and b which each other should return:

  • a negative value if a is smaller than b.
  • 0 or NaN if a and b are the same.
  • a positive value if a is larger than b.

In our compare function we tell sort to cast the elements to Numeric values and then use a subtraction of b from a. That returns a numeric value, positive, negative or even 0 thus return the expected value for the sort function.

console.log(largestFirst([900, 85, 1200]));
[1200, 900, 85]

The test works now as expected.