Sorting Arrays In JavaScript
Introduction
JavaScript provides us with a function called sort
that can be used to sort arrays. Let’s work through some examples to see how it works. This function sorts an array in place, that is, it modifies the original array (although it also returns the sorted array).
Master thy craft and thou shalt be respected among men.
— Fernando Basso
Sorting characters
We shall start with something that works as expected. An array of characters in no special order.
var chars = ['d', 'a', 'e', 'c', 'b'];
l(chars.sort());
// [ 'a', 'b', 'c', 'd', 'e' ]
As it can be seen, just doing chars.sort()
sorts our array ascendantly in the order thy appear in the alphabet.
Tip
If you don’t know what
l
is, see link:/javascript/javascript-console-log-warn-debug-bind-shortcuts.html[my post on console log helpers].
Sorting numbers - why doesn’t it work?
Now let’s see a situation where the default sorting algorithm does not work as expected.
var nums = [15, 10, 35, 301, 45, 20, 25, 101];
l(nums.sort());
// [ 10, 101, 15, 20, 25, 301, 35, 45 ]
Oops! The output is not numerically sorted in ascending order. That is because JavaScript sort
function treats elements as Unicode code points, and in this case 101
comes before 15
. Although this is not ASCII, man ascii
on a *nix system may help you understand this. You’ll see, for instance, how numbers come before uppercase letters, and these come before lowercase letters.
Sorting numbers - correct way
Luckily, JavaScript’s sort
method can take a function as argument which dictates how an array is to be sorted. This function takes two parameters a
and b
and must return a value less than, equal to, or greater than zero. Its return value tells the following to sort
:
-
less than zero →
a
should be beforeb
, ora
is less thanb
; -
greather than zero →
a
should be placed afterb
, ora
is greater thanb
; -
zero → both
a
andb
are equal and should remain in the position they currently are.
Let’s try again using a function to properly sort numbers in ascendant order.
Sorting numbers in ascending order.
var nums = [15, 10, 35, 301, 45, 20, 25, 101];
nums.sort(function(a, b) {
return a - b;
});
l(nums);
// [ 10, 15, 20, 25, 35, 45, 101, 301 ]
Ha! Now it works! To make it sort in descending order, we need to invert the result. To accomplish that we just need that in math we multiply any value for -1
(negative one) to invert the sign.
Sorting numbers in descending order.
var nums = [15, 10, 35, 301, 45, 20, 25, 101];
nums.sort(function(a, b) {
return (a - b) * -1;
});
// [ 301, 101, 45, 35, 25, 20, 15, 10 ]
Note that we pass the arguments a
and b
, and inside the function we subtract a
from b
and then multiply the result of the subtraction by -1
. Well, it so happens that mathematically, (a - b) * -1
is the same as b - a
. Pay attention to the order or a
and b
. Therefore, we could also using this to sort numbers in descending order:
Sorting numbers in descending order - another math approach.
var nums = [15, 10, 35, 301, 45, 20, 25, 101];
nums.sort(function(a, b) {
return b - a; // Note that a - b becomes b - a.
});
// [ 301, 101, 45, 35, 25, 20, 15, 10 ]
Preventing multiple pointless function definitions
If you are just sorting an array once or twice, there is no problem in writing the function we use as parameter to sort
right then and there. But if you use the same sorting callback function many times (perhaps inside a loop, or recursively), you are making the JavaScript engine recreate the same function over and over again for no good reason, which means the engine has to create the function, store memory to it, and later garbage-collect it, just to soon create another one, exactly the same as the previous one and repeat the process. In such cases it is probably better to define the callback function separately as to save CPU cycles and resources in general.
So, instead of doing:
nums.sort(function(a, b) {
// ...
});
We could do:
Defining sorting callback functions to use multiple times.
var sortNumsAsc = function sortNumsAsc(a, b) {
return a - b;
};
var sortNumsDesc = function sortNumsDesc(a, b) {
return b - a;
};
var evens = [8, 0, 2, 6, 4];
var odds = [7, 9, 1, 5, 3];
evens.sort(sortNumsAsc);
odds.sort(sortNumsDesc);
// And then we could use the same sorting functions over
// and over again should we have more sorting to do.
Important
When passing the callback function using this approach, do not use parenthesis. If you don’t understand why I am saying this, read link:/javascript/understanding-functions-in-javascript.html[my post on JavaScript functions].