linkedin Skip to Main Content
Categories

Guide to Sorting in JavaScript

Development

Like sorting your laundry? Or cleaning up a Lego spill into neat color-coded piles?

Yeah, me neither.

Because of its repetitive nature, sorting can be a bit of a chore at times. Unfortunately, sorting is as necessary for programming as it is in our daily lives.

Fortunately for us, however, it’s much easier to do as a JavaScript developer than it is in other areas of our lives.

In this guide, we’ll look at:

  • How to use JavaScript’s built in sort method
  • How to sort integer and string arrays
  • How to sort object arrays
  • How to sort non-ASCII characters
  • What Lodash is
    • How to use Lodash’s sortBy method
    • How to use Lodash’s orderBy method
  • A comparison of performance metrics for different sorting mechanisms

Organize your data using the JavaScript sort method

Sorting is the process of organizing data into meaningful groups so that it can be easily analyzed or processed.

JavaScript, like most other programming languages, includes a built-in sort method with the following syntax:

array.sort(compareFunction);
Code language: CSS (css)

Where the array is an array identifier containing the elements we want to sort, and the compareFunction is an optional function to enhance our sorting logic further. 

If a compare function is not supplied, the array elements are sorted by first converting them to strings, which are then compared and sorted in ascending order.

How the sort function works

The .sort() method uses an algorithm called “in-place” to sort the elements in our array. This type of algorithm does not require extra disk space to sort the items but may require a small, non-constant amount of extra memory space to run. Once the sorting operation is complete, it will return the same array, now sorted, without creating a new array in the process.

Here’s an example of utilizing sort() on an array of strings:

let states = ["Lagos", "New York", "Toronto", "Beijing", "Amsterdam"]; states.sort(); console.log(states); // returns: ["Amsterdam", "Beijing", "Lagos", "New York", "Toronto"]
Code language: JavaScript (javascript)

Here, we can see that our strings are sorted using the latin alphabet’s letter order. This means that “Aardvark” will come before “Zigzag”.

You can also apply .sort() to simple integers:

let luckyNumbers = [6, 1, 4, 7, 2, 5, 3]; luckyNumbers.sort(); console.log(luckyNumbers); // returns: [1, 2, 3, 4, 5, 6, 7]
Code language: JavaScript (javascript)

However, when we try to sort through integers with larger values, our sort function appears to fail:

let luckyNumbers = [100, 40, 10, 300, 20, 50, 30]; luckyNumbers.sort(); console.log(luckyNumbers); // returns: [10, 100, 20, 30, 300, 40, 50]
Code language: JavaScript (javascript)

So, what is causing this? As previously stated, if a compare function is not provided in the .sort() operation, all array elements are sorted by first converting them to strings and then comparing them. 

In other words, while our .sort()  method continues to return an array of integers, we are actually attempting to sort the following array:

["100", "40", "10", "300", "20", "50", "30"]
Code language: JSON / JSON with Comments (json)

And alphabetically, “100” comes before “20”. We can quickly fix this by writing our own custom compare function instead of using JavaScript’s default.

Use custom logic to sort your data by creating a compare function

The compare function takes two parameters, commonly named a and b, where a is the first element for comparison and b is the second. Because b is the second value, it is commonly referred to as the comparator. This function then runs during the .sort() method and assists it in determining which item in the array should come first in the results.

Furthermore, the compare function must be written in such a way that:

  • It returns a negative number if the first comparator should be sorted before the second.
  • It returns 0 (zero) if the comparators should be equal or maintain the same order.
  • It returns a positive number if the second comparator should be sorted before the first.
`compareFn(a, b)` return valuesort order
> 0sort `a` after `b`
< 0sort `a` before `b`
=== 0keep original order of `a` and `b`
Table Credit: MDN

To better understand this, imagine we have a three-element array of numbers:

let numList = [4, 5, 3];
Code language: JavaScript (javascript)

And, we’d like to sort it in descending order. We could write a compare function and apply it to our array in the following way:

function compare(a, b) {   return b - a; } numList.sort(compare);
Code language: JavaScript (javascript)

Behind the scenes, .sort() will call the compare function repeatedly as it runs through the entire array, picking two elements at a time and using the logic in our compare function to determine which item comes before which. For example, let’s look at what happens when we sort the first two numbers in the array:

compare(4, 5);

According to our compare function, the code above will return 1 (i.e., 5 – 4), which is a positive number. Looking at our comparison table, we must return a positive number if we want the second comparator (or, value) to be sorted before the first, which translates to 5 coming before 4, so we now have [5, 4] stored in memory; it will keep doing this process for each element in the array until the desired result is obtained.

Additionally, while the preceding example used a named compare function, we’re also able to  use inline functions instead.

Here’s a simplified implementation example which sorts our previous large integer array in ascending order:

let luckyNumbers = [100, 40, 10, 300, 20, 50, 30]; luckyNumbers.sort(function (a, b) { return a - b; }); console.log(luckyNumbers); // returns: [10, 20, 30, 40, 50, 100, 300]
Code language: JavaScript (javascript)

And here’s an example of sorting the same array in descending order, but simplified even further by using the ES6 arrow function:

let luckyNumbers = [100, 40, 10, 300, 20, 50, 30]; luckyNumbers.sort((a, b) => b - a); console.log(luckyNumbers); // returns: [300, 100, 50, 40, 30, 20, 10]
Code language: JavaScript (javascript)

While using math in our compare function (eg b-a) to determine our comparison value works well with integers, it’s often not viable when working with other data types, such as strings and booleans. Instead, we can include logic (such as adding if/else statements) in our compare function. We can then return -1, 1, or 0 based on this logic.

How to sort different data types

Now that we fully understand how the compare function works, let’s look at some examples to see where it might be helpful.

How to sort an array of integers and strings

Let’s say that we have a list of strings and integers, like so:

[123, "John", "Zuck", 345, "Ben", "Alan", 678, "Mom"];
Code language: CSS (css)

And we want to sort them such that:

  • Numbers come first, sorted numerically
  • Strings come second, sorted alphabetically

We could write some custom comparison code, like so, to achieve this effect:

let contacts = [123, "John", "Zuck", 345, "Ben", "Alan", 678, "Mom"]; contacts.sort((a, b) => {   if (typeof a === "number" && typeof b === "number") {     return a - b;   }   if (typeof a === "number") {     return -1;   }   if (typeof b === "number") {     return 1;   } else {     return a > b ? 1 : -1;   } }); console.log(contacts);
Code language: JavaScript (javascript)

The final output of this function on the array would be:

[123, 345, 678, "Alan", "Ben", "John", "Mom", "Zuck"]
Code language: JSON / JSON with Comments (json)

In our compare function, we first define an if statement to see if both of our comparators are integers, and then we sort them in ascending order using the previous a - b syntax. 

We also used two more if statements to determine whether the first or only the second comparator is an integer and sorted them accordingly. 

Finally, if our comparators are not integers, we used an else statement and a ternary operation to sort them by checking which string is greater than the other and returning an integer value for our preferred sort operation.

Sorting an array of objects

We can also use a compare function to sort an array of objects. Consider the following list of popular JavaScript libraries and their GitHub star count:

let jsLibraries = [   {     name: "React",     star: 194478,   },   {     name: "Vue",     star: 199199,   },   {     name: "Angular",     star: 83716,   },   {     name: "Lodash",     star: 54288,   }, ];
Code language: JavaScript (javascript)

We can sort it by library name, ascending:

jsLibraries.sort((a, b) => {   if (a.name > b.name) {     return 1;   } else {     return -1;   } }); /* returns: [   { name: 'Angular', star: 83716 },   { name: 'Lodash', star: 54288 },   { name: 'React', star: 194478 },   { name: 'Vue', star: 199199 } ] */
Code language: JavaScript (javascript)

And, because the number of stars is an integer, we can use the previous b - a syntax to sort in descending order (i.e., libraries with the most stars come first):

jsLibraries.sort((a, b) => { return b.star - a.star; }); /* returns: [ { name: 'Vue', star: 199199 }, { name: 'React', star: 194478 }, { name: 'Angular', star: 83716 }, { name: 'Lodash', star: 54288 } ] */
Code language: JavaScript (javascript)

Sorting non-ASCII characters

So far, our sort function has performed admirably with strings. However, when we attempt to sort an array of strings containing special (non-ASCII) characters, the sort method will not work as expected. Consider the following example:

const frenchWords = ["résumé", "premier", "communiqué", "café", "adieu", "éclair"]; frenchWords.sort(); console.log(frenchWords); // returns: ["adieu", "café", "communiqué", "premier", "résumé", "éclair"]
Code language: JavaScript (javascript)

As seen in this example, the word “éclair” was the last in the array, owing to the fact that it begins with a special character. We can easily fix this by including an additional .localCompare() method in our sort compare function.

The .localeCompare() method allows us to compare the order of two different strings, i.e., which one comes first or if both strings are in the same order. We can apply this method in a custom compare function to sort non-ASCII characters, such as with languages that include accents or special characters.

This also allows for much flexibility because the .localeCompare() method will return a negative number if the reference string comes before the other string we’re comparing with, a negative number if it occurs after, and 0 if they are equivalent.

To fix our previous example, we can simply apply the .localCompare() method like below:

const frenchWords = ["résumé", "premier", "communiqué", "café", "adieu", "éclair"]; frenchWords.sort((a, b) => a.localeCompare(b, "fr")); console.log(frenchWords); // returns: ["adieu", "café", "communiqué", "premier", "résumé"]
Code language: JavaScript (javascript)

In this example, we applied the .localCompare() method to compare the first comparator a with the second b so that the strings will be sorted in order accordingly. 

And, as you might have noticed, there is  an optional “fr” locale added as the second argument to the .localeCompare() method so that our strings will be compared by their order in the French language. In addition to the locale, the .localeCompare() method also accepts additional parameters such as case sensitivity.

Use Lodash for advanced sorting logic

Lodash is a JavaScript library that provides utility methods for everyday programming tasks such as array, number, object, string, and other data structure manipulation. One of these utility methods helps in sorting arrays. We’ll see how this works by recreating our previous examples with the lodash method. 

First, you can install lodash via npm with the following command:

npm i lodash

And once the installation process is complete, you can import the lodash core with:

const _ = require("lodash");
Code language: JavaScript (javascript)

Do simple sorting using Lodash’s _.sortBy()

The Lodash _.sortBy() method is similar to the JavaScript native .sort() method in that it takes the array to sort as the first parameter and the sort logic (i.e. the compare function) as the second. Unlike .sort(), however, the _.sortBy() method does not directly modify the original array and instead creates a new copy during its execution.

Furthermore, the _.sortBy() method can only be used to sort arrays in ascending order. However, it is more intuitive than the native .sort() method in that you can simply pass a sort order or the key(s) you want to sort with (when working with a collection) and avoid writing any sort logic.

Using our previous example, we can use lodash to sort an array of integers or strings as follows:

let states = ["Lagos", "New York", "Toronto", "Beijing", "Amsterdam"]; console.log(_.sortBy(states)); // returns: ["Amsterdam", "Beijing", "Lagos", "New York", "Toronto"] /* . . . */ let luckyNumbers = [100, 40, 10, 300, 20, 50, 30]; console.log(_.sortBy(luckyNumbers)); // returns: [10, 20, 30, 40, 50, 100, 300]
Code language: JavaScript (javascript)

You’ll also notice that we didn’t need to write any sorting logic for large numbers!

Additionally, in the case of our array of objects, where we sorted the top JavaScript libraries example from earlier, we could simply pass our preferred sorting key as follows:

// sort by name console.log(_.sortBy(jsLibraries, "name")); // sort by star console.log(_.sortBy(jsLibraries, "star"));
Code language: JavaScript (javascript)

How to do complex sorting using Lodash’s _.orderBy()

Unfortunately, the _.sortBy() method can only be used to sort arrays in ascending order. However, lodash includes an additional _.orderBy() method that allows for more flexibility. Its syntax is pretty similar to  _.sortBy(), except that it accepts an optional third parameter that lets us specify the sort order:

const _ = require("lodash"); let jsLibraries = [ { name: "React", star: 194478, }, { name: "Vue", star: 199199, }, { name: "Angular", star: 83716, }, { name: "Lodash", star: 54288, }, ]; console.log(_.orderBy(jsLibraries, "name", "desc")); /* returns: [ { name: 'Vue', star: 199199 }, { name: 'React', star: 194478 }, { name: 'Lodash', star: 54288 }, { name: 'Angular', star: 83716 } ] */
Code language: JavaScript (javascript)

Additionally, we could specify a different sort order for different object keys in a single sort:

const _ = require("lodash"); var users = [   { name: "Alex", age: 48 },   { name: "Jane", age: 34 },   { name: "Alex", age: 40 },   { name: "Jane", age: 36 }, ]; console.log(_.orderBy(users, ["name", "age"], ["asc", "desc"])); /* returns: [   { name: 'Alex', age: 48 },   { name: 'Alex', age: 40 },   { name: 'Jane', age: 36 },   { name: 'Jane', age: 34 } ] */
Code language: JavaScript (javascript)

In the example above, we’ve used the _.orderBy() method to sort our array by name in ascending order and age in descending order.

Comparing performance

To compare the performance of the native JavaScript .sort() method and the lodash _.sortBy() method, I created a simple benchmark test using our previous top JavaScript libraries array. The results: the native JavaScript method performed significantly better than lodash.

A benchmark of the native comparison function versus the lodash method of sortBy. The lodash method is 81.47% slower. Benchmark hosted on JSBench.ME

This is not surprising given that Lodash’s method is loaded from a third-party library rather than being built directly into the JavaScript engine. Its approach also degrades performance because, unlike the native .sort() method, it does not directly manipulate the original array but creates a modified copy.

To make the comparison more fair, I performed a second test with the same array, but this time using the spread operator to copy the original array before sorting with the .sort() method.

The native benchmark now uses the spread operator to create a new array. Lodash is now only 68% slower than native. Benchmark hosted on JSBench.ME

While the native .sort() method remains significantly faster, the slowness of the lodash _.sortBy() method has decreased from 81% to 68%.

Conclusion

This tutorial taught us how to use the .sort() method in JavaScript while experimenting with various data structures. We also covered how to do equivalent sorting with the lodash _.sortBy() and _.orderBy() methods and finally compared the performance of the two options, with the JS native sort outperforming the latter.