Sort arrays in JavaScript - object arrays and primitive arrays
Data being returned from an API cannot always be trusted to be sorted. If you have developed your API yourself, you can of course make sure it is, but if the source is from a third-party or similar - it will almost always be necessary to rely on doing sorting by ourselves.
In todays guide, we will check out how we can use the Array.prototype.sort() function, and how we can change the implementation to suite our application.
Basic example
Let us start simple. We have an unsorted array of numbers we want to sort in ascending order. The built in sorting in JavaScript will do this for us.
[5, 3, 6, 7].sort(); // [3, 5, 6, 7]
How about strings?
We now want to sort on names. The built in sort will take care of this as well.
["Peter", "Richard", "Thomas", "Anders"].sort(); // ['Anders', 'Peter', 'Richard', 'Thomas']
In above example, the built in sort is handling the sorting very well. But what if we want the order to be descending? Or if we have an array of dates? Or an object with some value we want to compare with? Then we need to do some work...
Implementing our own compare function
Luckily, the sort() allows us to send in our own compare function. So, now we want to take the above examples, and sort them descending instead. Let's create our descending sort function.
const sortDescending = (a, b) => { if (a > b) { return -1; } else if (b > a) { return 1; } return 0; };
All right, what is this stuff doing? Basically, it checks two values at the time from the array. If the value (a) is greater than (b) it will return -1, if (b) is greater than (a) it will return 1 and if they are the same, it will return 0. The -1 and 1 value will make the array swap the values, and returning 0 will do nothing since they are the same.
The ascending function that are the default function, looks like this:
function compareFn(a, b) { if (a is less than b by some ordering criterion) { return -1; } if (a is greater than b by the ordering criterion) { return 1; } // a must be equal to b return 0; }
And what we are actually doing, is basically reversing it to sort descending instead.
Let's try it out
[5, 3, 6, 7] .sort(sortDescending) // [7, 6, 5, 3] [("Peter", "Richard", "Thomas", "Anders")].sort(sortDescending); // ['Thomas', 'Richard', 'Peter', 'Anders']
Cool, now we can sort descending!
Arrays with objects?
Often, we are dealing with arrays of objects. And they need to be sorted as well, right?
Let's take a look how that can be done then..
const persons = [ { name: "Jack", age: 12 }, { name: "John", age: 5 }, { name: "Steven", age: 52 }, ];
Now, we cannot use the built in sort either since it cannot compare an object with another object. So, lets create our compare function that handles our persons:
const sortPeople = (a, b) => { if (a.age < b.age) { return -1; } else if (b.age < a.age) { return 1; } return 0; };
So, a and b are now person objects. So our function will instead sort by their age instead.
Let's try
persons.sort(sortPeople); // {name: 'John', age: 5} // {name: 'Jack', age: 12} // {name: 'Steven', age: 52
Sort dates?
Dates can always be a little tricky to work with. But lets see if we can sort an object with a e.g timestamp.
const dataWithTimestamp = [ { timestamp: new Date("2012-01-23") }, { timestamp: new Date("2002-04-05") }, { timestamp: new Date("1998-02-17") }, ];
And our sort function..
const sortDates = (a, b) => { if (a.timestamp.getTime() < b.timestamp.getTime()) { return -1; } else if (b.timestamp.getTime() < a.timestamp.getTime()) { return 1; } return 0; };
The trick is to use the getTime() function which will return milliseconds since the epoch (January 1, 1970, UTC).
Let's try it out
dataWithTimestamp.sort(sortDates); // { timestamp: "1998-02-17" } // { timestamp: "2002-04-05" } // { timestamp: "2012-01-237" }
Sort nested objects
Nested object can be cumbersome to work with, and that goes for sorting them as well. Let's see an example of nested objects and how we can sort them.
const todos = [ { type: "Cleaning", chores: [ { name: "Living room", priority: 4 }, { name: "Bathroom", priority: 2 }, ], }, { type: "Shopping", chores: [ { name: "Clothes", priority: 3 }, { name: "Groceries", priority: 1 }, ], }, ];
In this example, we want to sort the chores array so the one with the highest priority comes first (1 is considered highest), and then we want to sort the todos array to have the object with the highest priority chores at the top - meaning, we want our Shopping chore to be at the top.
We start with out sortChores function
const sortChores = (a, b) => { if (a.priority < b.priority) { return -1; } else if (a.priority > b.priority) { return 1; } return 0; };
In this example, we are expecting chores objects, hence, we can access the priority property and sort with it.
Create our sort todos
const sortTodos = (a, b) => { if (a.chores[0]?.priority < b.chores[0]?.priority) { return -1; } else if (a.chores[0].priority > b.chores[0]?.priority) { return 1; } return 0; };
In this example, we are expecting a todo object with sorted chores to come in.
Let's try it out
todos .map((todo) => ({ ...todo, chores: todo.chores.sort(sortChores) })) .sort(sortTodos);
We are using the built in function map. Unfamiliar with map? Read our guide on it here.
Output
[ { "type": "Shopping", "chores": [ { "name": "Groceries", "priority": 1 }, { "name": "Clothes", "priority": 3 } ] }, { "type": "Cleaning", "chores": [ { "name": "Bathroom", "priority": 2 }, { "name": "Living room", "priority": 4 } ] } ]
Cool. Now we sorted each chore and also each todo in priority order.
Outro
In todays guide we took a look sorting arrays in JavaScript. We explored the built in sorting algorithm that JavaScript is providing by default and we also showed how we can pass in our own function to control the sorting on our own. We also showed how we can sort objects and objects with nested arrays in it as well as sorting dates.
I hope you found this guide helpful. If any feedback or if you feel I missed something, just hit me up with an email here. All the best!