# Number sorting gotcha with JavaScript

[Canonical article](https://www.ashryan.io/writing/number-sorting-gotcha-with-javascript/)

Published: 2020-11-23

Problem: Sorted arrays are coming back in an unexpected order... sometimes. Safari is behaving differently than Chrome and Node.js. Let’s look at what to do.

There’s now a small, solid group working on [Astoria Digital’s MuckRock dataviz project](https://www.ashryan.io/writing/muckrock-api/). In fact, Chris DeLuca recently [published a post](https://www.chrisdeluca.me/article/rendering-simple-bar-chart-nivo/?ref=ashryan.io) about some developer onboarding issues with the dataviz library we are using for the project. We have prevailed, but it took some putting our heads together last weekend.

While we were troubleshooting our new visualization, we ran into another issue JavaScript developers frequently encounter: return values coming back in an unexpected order… *sometimes*. In this case, the issue was browser-specific, where a list’s order was fine in Safari, but seemingly random in Chrome.

## A simple version of the problem

Say you have a list of prices that you want to sort:

```plaintext
const prices = [3, 5, 370, 8];
const sortedPrices = prices.sort();
```

What do you think `sortedPrices` will look like?

For Chrome and Node.js, you are correct if you guessed:

```plaintext
[ 3, 370, 5, 8 ]
```

Because ([via MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort?ref=ashryan.io)):

> The default sort order is ascending, built upon converting the elements into strings, then comparing their sequences of UTF-16 code units values.

So the output above is the correct ascending order when the numbers are coerced to strings:

```plaintext
console.log("3" < "350"); // true

console.log("350" < "5"); // true; gotcha!
```

The wild thing here is that *Safari does what you would expect*, leading to more confusion:

```plaintext
[ 3, 5, 8, 370 ]
```

So using `Array.prototype.sort()` with no argument is not going to work for reliably sorting numbers. To make sure the sort behaves as we expect *everywhere*, we’ll have to supply our own compare function.

## This won’t work

We could try using a greater-than/less-than comparitive operator:

```plaintext
const sortedPrices = prices.sort((second, first) => first < second);
```

But recall that the parameters you receive in the callback (`second` and `first`) are strings, not numbers, so here’s what you’ll get:

```plaintext
[ 3, 5, 370, 8 ]
```

Because:

```plaintext
“3” < “5”      // true
“5” < “370”    // true
“370” < “8”    // true!
```

The comparison operators don’t coerce strings to numbers, so you just get a different flavor of the problem we saw when passing no argument to `Array.prototype.sort()`.

## But this will work

JavaScript will coerce the string parameters to numbers if we perform a mathematic operation on them. So instead of *comparing*, we can simply subtract them:

```plaintext
const prices = [3, 5, 370, 8];
const sortedPrices = prices.sort((second, first) => second - first);
```

If `second - first` is a negative number, `second` will be sorted *down* in the array, step-by-step, until it ends up in its correct spot in the ascending order.

Our new compare function gives us:

```plaintext
[ 3, 5, 8, 370 ]
```

Problem sorted.
