Custom Array Sort Algorithms in JavaScript

JavaScript Joel - Oct 22 '20 - - Dev Community

JavaScript's Default Array Sort

JavaScript's Array.sort defaults to a String sort. This catches many people off guard when attempting to sort an Array of type Number.

// ❌ Default search is a String search
const numbers = [10, 1, 3, 15]
numbers.sort() // [ 1, 10, 15, 3 ]
Enter fullscreen mode Exit fullscreen mode

In the above example, each Number is converted to a String and then sorted using a String sort.

At first, this can seem like a WTF JavaScript moment, but this happens because an Array can contain mixed elements and JavaScript doesn't know how it should sort. So sort defaults to a String sort.

const array = [1, 2, 3, 'Joel', 4, { userId: 123 }]
Enter fullscreen mode Exit fullscreen mode

When we want something other than a String sort, we have to be explicit.

Custom Sort Compare Function

Creating a custom sort compare function is pretty easy. The function takes two elements, then we return -1 if the first is lower and 1 if it's higher. 0 for the same.

const compareFunction = (a, b) => {
    // Pseudo Code
    if (a is less than b) return -1
    if (a is more than b) return 1
    return 0
}
Enter fullscreen mode Exit fullscreen mode

Then pass that function to the sort method.

myArray.sort(compareFunction)
Enter fullscreen mode Exit fullscreen mode

This flexibility will allow us to be creative with our sorting algorithms.

Number Sort

To sort a Number Array we could create a custom compareNumbers function and pass that into Array.sort.

const compareNumbers = (a, b) => a - b

const numbers = [10, 1, 3, 15]
numbers.sort(compareNumbers) // [ 1, 3, 10, 15 ]
Enter fullscreen mode Exit fullscreen mode

Custom Object Sort

Let's say we had some data that looks like this:

const customers = [
    { id: 1, orders: ['a-1000', 'x-2000', 'c-8000'] },
    { id: 2, orders: ['a-1010'] },
    { id: 3, orders: ['a-1040', 'c-8050'] },
]
Enter fullscreen mode Exit fullscreen mode

Our requirement is to sort by the number (length) of orders. So the order should be 2, 3, 1.

We can do that with a custom compareOrderLength function that will sort by customer.orders.length.

const compareOrderLength = (a, b) => a.orders.length - b.orders.length

customers.sort(compareOrderLength)
/**
 * [
 *   { id: 2, orders: [ 'a-1010' ] }, 
 *   { id: 3, orders: [ 'a-1040', 'c-8050' ] }, 
 *   { id: 1, orders: [ 'a-1000', 'x-2000', 'c-8000' ] }
 * ]
 */
Enter fullscreen mode Exit fullscreen mode

Complex Custom Sorting

I recently had a use case where an API was returning data that looked like this.

// API Response
["1", "10", "2", "BLA", "BLA2", "3"]
Enter fullscreen mode Exit fullscreen mode

The Array contained all String items, but the business wanted the items to display like "1, 2, 3, 10, BLA, BLA2".

That meant, I had to detect when the String was a Number and Sort the "numbers" first and the text after.

As complex as that sounds, the sort algorithm wasn't too bad.

const isNumeric = (num) => !isNaN(num)

const customCompare = (a, b) => {
    if (isNumeric(a) && !isNumeric(b)) return -1
    if (!isNumeric(a) && isNumeric(b)) return 1
    if (isNumeric(a) && isNumeric(b)) return a - b
    return a < b ? -1 : 1
}

// [ '1', '2', '3', '10', 'BLA', 'BLA2' ]
Enter fullscreen mode Exit fullscreen mode

End

So just remember the default Array sort is a String sort. To sort by anything else, you must create a compare function and pass that into sort.

Cheers 🍻

Photo by Kelly Sikkema on Unsplash

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .