DEV Community

Cover image for Mastering array sorting in JavaScript: a guide to the sort() function
Salvietta150x40
Salvietta150x40

Posted on • Originally published at ma-no.org

Mastering array sorting in JavaScript: a guide to the sort() function

In this article, I will explain the usage and potential of the sort() function in JavaScript.

 

What does the sort() function do?

 

The sort() function allows you to sort the elements of an array object. It can sort the elements in either the default ascending order or according to a custom sorting function.

By default, the function sorts the elements in ascending order based on their string Unicode values. It converts the elements to strings and then arranges them using Unicode values.

 

What is Unicode?

 

Unicode is a standard that assigns a unique numeric value, known as a code point, to every character used in writing systems worldwide. It enables computers to handle and represent various languages, symbols, and tastes consistently.

For example, in the English Latin alphabet:

- U+0041 to U+005A represents the Latin capital letters (A-Z).
- U+0061 to U+007A represents the Latin small letters (a-z).

So, for instance, the word "Apple" in the Latin alphabet (English) is represented in Unicode as:

A: U+0041

p: U+0070

p: U+0070

l: U+006C

e: U+0065

 

How does sort() utilize Unicode tastes?

 


The sort() function employs a sorting algorithm to sort the array. It can use various sorting algorithms such as bubble sort, quicksort, heapsort, or mergesort, depending on factors like array size, data types, and optimization strategies implemented by the JavaScript engine.

The JavaScript engine executes the code and is responsible for interpreting and running JavaScript programs. It can be part of web browsers, server-side JavaScript platforms, or standalone JavaScript runtime environments.

Among the sorting algorithms mentioned, quicksort or its variations are commonly used for sorting arrays in JavaScript.

If you're interested in learning more about the quicksort algorithm, you can check out resources like the W3Resource website.

How to use the sort() function in JavaScript
Now that we understand how sort() works internally, let's see how to use it.

To use the function, simply call {array}.sort() . This will sort the elements in the default ascending order, as described earlier.

 

javascript
const tastes = [
"Margherita",
"Napoletana",
"Quattro Formaggi",
"Primavera",
"Marinara",
"Boscaiola",
"Bufala",
];
const sortedArray = tastes.sort();
// Output:
["Boscaiola", "Bufala", "Primavera", "Margherita", "Marinara", "Quattro Formaggi", "Napoletana"];

 

As you can see in the example, the names of the tastes have been sorted in ascending order based on their Unicode representation.

If you want to have them sorted in descending alphabetical order, you can chain the reverse() function after sort() . This will reverse the order of the elements once they have been sorted.

 

What about sorting numbers?

 

Let's explore it:

 

const numbers = [9, 3, 12, 11, 40, 28, 5];
const sortedNumbers = numbers.sort();
console.log(sortedNumbers);
// Output:
[11, 12, 28, 3, 40, 5, 9];

 

Mmmmmmh ,the result is not sorted in the expected order. Why?

Well, remember when I mentioned that the default sorting method uses Unicode character sorting after converting the elements to strings? That's the reason. The numbers are converted to their string equivalents and then sorted based on Unicode values.

As a consequence, all the numbers starting with '1' come before any other numbers. Therefore, '11' is sorted before '3', and so on.

Let's examine the Unicode values for these numbers:

- 11: U+0031 U+0031
- 12: U+0031 U+0032
- 28: U+0032 U+0038
- 3: U+0033
- 40: U+3034 U+0030
- 5: U+3035
- 9: U+3039

As you can see, if we sort based on Unicode tastes, the comparison between '1' and '3' results in '0031' being less than '0033'. Consequently, the numbers starting with '1' will be pushed to the front of the array.

You might find this behavior annoying. But don't worry, there's a solution: using custom compare functions.

 

How to Use a Custom Sort Function

 

As mentioned earlier, the sort() function can accept a custom comparison function as an argument.

 

sort(compareFn?: ((a: never, b: never) => number) | undefined): never[]

 

The comparison function is used to determine the order of the elements. It is expected to return a negative value if the first argument is less than the second argument, zero if they are equal, and a positive value otherwise. If the comparison function is omitted, the elements are sorted in ascending ASCII character order.

For example:

 

[11, 2, 22, 1].sort((a, b) => a - b);

 

This code sorts an array in place. The method mutates the array and returns a reference to the same array.

So, what does all of this mean?

The custom comparison function has specific expectations. It requires you to return certain values:

- -1: if the value on the left is less than the value on the right.
- 0: if the value on the left is equal to the value on the right.
- 1: if the value on the left is greater than the value on the right.

In simpler terms, returning -1 moves the item to the left (before the compared value), returning 0 keeps it in place, and returning 1 moves the item to the right (after the compared value).

Now let's explore some examples to understand how it works.

Referring to the previous example where we struggled to sort an array of numbers, we can fix this by using a custom comparison function:

 

const numberSortFn = (a, b) => {
if (a < b) {
return -1;
} else if (a === b) {
return 0;
} else {
return 1;
}
};
const numbers = [9, 3, 12, 11, 40, 28, 5];
const sortedNumbers = numbers.sort(numberSortFn);
console.log(sortedNumbers);
// Output:
[3, 5, 9, 11, 12, 28, 40];

 

As you can see, the array is now sorted in numerical ascending order as we expected. The reason it works differently is because the less than operator now compares the values as numbers rather than strings.

 

Other Uses of the Custom Comparison Function

 

In addition to sorting arrays of numbers, you can also utilize the custom comparison function to sort objects based on their properties. Let's explore an example of sorting an array of objects (books) based on their year of publication.

 

const books = [
{ title: "Book A", year: 2010 },
{ title: "Book B", year: 2005 },
{ title: "Book C", year: 2018 },
];
const booksSortedByYearAsc = books.sort((a, b) => a.year - b.year);
console.log(booksSortedByYearAsc);
// Output:
[
{ title: "Book B", year: 2005 },
{ title: "Book A", year: 2010 },
{ title: "Book C", year: 2018 },
];


```


 

In this example, we provide a custom comparison function that compares the objects based on their `.year` property. By subtracting `b.year` from `a.year`, we can achieve ascending order sorting based on the year of publication.

This technique allows you to sort objects in arrays based on any property you choose. You simply need to modify the comparison function accordingly to compare the desired properties.

By utilizing custom comparison functions, you gain flexibility in sorting arrays of various data types and objects based on specific criteria.

 

Sorting based on the content of the string

 

Let's take our sorting capabilities a step further. Imagine we have a list of attendees at a seminar, and we want to generate a register. However, we want to prioritize the doctors and have them listed at the top, as they are the keynote speakers.

We can achieve this using a custom comparison function:

 

const names = ["Mike Smith", "Dr. Johnson", "John Doe", "Dr. Williams"];
names.sort((a, b) => {
if (a.startsWith("Dr.") && !b.startsWith("Dr.")) {
return -1;
} else if (!a.startsWith("Dr.") && b.startsWith("Dr.")) {
return 1;
} else {
return a.localeCompare(b); // sort alphabetically
}
});
console.log(names);
// Output:
["Dr. Johnson", "Dr. Williams", "John Doe", "Mike Smith"];

 

In this example, we define a custom comparison function that checks if a string starts with "Dr." or not. If the first string starts with "Dr." and the second one does not, we return -1, indicating that the first string should be placed before the second string in the sorted array. Conversely, if the first string does not start with "Dr." and the second one does, we return 1 to indicate the opposite order.

For cases where neither string has "Dr." at the beginning, we resort to using the `localeCompare` function. This function performs an alphabetical comparison using Unicode values, similar to the default behavior discussed earlier in this article.

By incorporating custom comparison logic, you can prioritize specific patterns or values in your sorting process, enabling you to achieve more specialized sorting results based on the content of the strings.

 

Strings of Numbers and Letters

 

Suppose you have an array that contains a mixture of numbers and letters, and you want to sort it in a specific way. Your goal is to have the numbers appear before the letters, and within each group, you want the elements to be sorted numerically and alphabetically, respectively. Here's how you can achieve that using a custom comparison function:

 

const items = ["b", "3", "a", "2", "c", "1"];

items.sort((a, b) => { const aIsNumber = !isNaN(a); const bIsNumber = !isNaN(b); if (aIsNumber && !bIsNumber) { return -1; // Numbers should be sorted before letters } else if (!aIsNumber && bIsNumber) { return 1; // Letters should be sorted after numbers } else if (aIsNumber && bIsNumber) { return a - b; // Sort numbers numerically } else { return a.localeCompare(b); // Sort letters alphabetically } }); console.log(items) // Output: ["1", "2", "3", "a", "b", "c"];

 

In this example, we first determine whether each value is a number or not using the isNaN() function. By checking if the negation of isNaN() is `true`, we can identify if the value is a number.

Based on this information, we apply the following logic:

- If `a` is a number and `b` is not a number, we return -1 to indicate that numbers should be sorted before letters.
- If `a` is not a number and `b` is a number, we return 1 to indicate that letters should be sorted after numbers.
- If both `a` and `b` are numbers, we subtract `b` from `a` (`a - b`). This allows us to sort the numbers numerically by comparing the numeric values.
- If none of the above conditions are met, we resort to using `localeCompare()` to sort the letters alphabetically.

By incorporating this custom comparison logic, we can achieve the desired sorting order, where numbers appear before letters, and within each group, the elements are sorted numerically and alphabetically, respectively.

 

 

Strings of Numbers and Letters

 

Suppose you have an array that contains a mixture of numbers and letters, and you want to sort it in a specific way. Your goal is to have the numbers appear before the letters, and within each group, you want the elements to be sorted numerically and alphabetically, respectively. Here's how you can achieve that using a custom comparison function:

 

const items = ["b", "3", "a", "2", "c", "1"];
items.sort((a, b) => {
const aIsNumber = !isNaN(a);
const bIsNumber = !isNaN(b);
if (aIsNumber && !bIsNumber) {
return -1; // Numbers should be sorted before letters
} else if (!aIsNumber && bIsNumber) {
return 1; // Letters should be sorted after numbers
} else if (aIsNumber && bIsNumber) {
return a - b; // Sort numbers numerically
} else {
return a.localeCompare(b); // Sort letters alphabetically
}
})
// Output:
["1", "2", "3", "a", "b", "c"];

 

In this example, we first determine whether each value is a number or not using the isNaN() function. By checking if the negation of isNaN() is `true`, we can identify if the value is a number.

Based on this information, we apply the following logic:

- If `a` is a number and `b` is not a number, we return -1 to indicate that numbers should be sorted before letters.
- If `a` is not a number and `b` is a number, we return 1 to indicate that letters should be sorted after numbers.
- If both `a` and `b` are numbers, we subtract `b` from `a` (`a - b`). This allows us to sort the numbers numerically by comparing the numeric values.
- If none of the above conditions are met, we resort to using `localeCompare()` to sort the letters alphabetically.

By incorporating this custom comparison logic, we can achieve the desired sorting order, where numbers appear before letters, and within each group, the elements are sorted numerically and alphabetically, respectively.

In the code snippet provided, there is a custom comparison function used to sort an array containing both numbers and letters. The logic is designed to prioritize sorting based on the type (number or letter) and then further refine the order within each group. Let's break down the logic step by step:

  1. Checking if values are numbers: The isNaN() function is used to check if a value is not a number. By negating the result using the logical NOT operator (!) , aIsNumber and bIsNumber are set to true if the corresponding value is a number and false otherwise.

  2. Sorting numbers before letters: The first if statement checks if a is a number ( aIsNumber is true) and b is not a number ( bIsNumber is false). In this case, we return -1 to indicate that a should come before b in the sorted order.

  3. Sorting letters after numbers: The second if statement checks if a is not a number ( aIsNumber is false) and b is a number ( bIsNumber is true). Here, we return 1 to indicate that b should come after a in the sorted order.

  4. Sorting numbers numerically: The third if statement checks if both a and b are numbers (aIsNumber and bIsNumber are both true). In this case, we perform a numeric comparison by subtracting b from a. The result of this subtraction determines the relative order of the numbers.

  5. Sorting letters alphabetically: If none of the previous conditions are met, it means both a and b are strings (letters). We then use the localeCompare() function to perform an alphabetical comparison and determine the order of the letters.

By applying this custom comparison logic, the array items is sorted in the desired order. Numbers appear before letters, and within each group, the elements are sorted numerically and alphabetically, respectively. The resulting sorted array is ["1", "2", "3", "a", "b", "c"] .

 

Explanation of Sorting in Descending Order

 

In the code snippet provided, the goal is to sort an array of tastes in descending order. Instead of using the sort(compareFn) approach, the sort(compareFn) function is used with a custom comparison function to achieve the desired result. Let's break down the code:

 

javascript
const tastes = [
"Margherita",
"Napoletana",
"Quattro Formaggi",
"Primavera",
"Marinara",
"Boscaiola",
"Bufala",
];
const sortedArray = tastes.sort((a, b) => b.localeCompare(a));
console.log(sortedArray);
// Output:
["Quattro Formaggi", "Primavera", "Napoletana", "Margherita", "Marinara", "Bufala", "Boscaiola"]

 

The sort() function takes a comparison function as an argument, which defines the custom sorting logic. In this case, the comparison function (a, b) => b.localeCompare(a) is used.

By default, the localeCompare() function compares strings in ascending alphabetical order. However, to achieve descending order, the comparison is inverted by comparing `b` to `a` instead of the usual `a` to `b`. This reversal of the operands ensures that the comparison is performed in the desired descending order.

As a result, the array `tastes` is sorted in descending order, and the sorted array `sortedArray` contains the elements ["Napoletana", "Quattro Formaggi", "Marinara", "Margherita", "Primavera", "Bufala", "Boscaiola"]` .

It's worth noting that this approach works specifically for sorting an array of strings. If you're sorting numbers or objects based on a specific property, the comparison logic will differ.

When it comes to the performance of sorting arrays, there are several factors to consider, including the JavaScript engine, array size, and complexity of the custom sorting function. The performance can vary based on these factors.

In general, the built-in sort() method tends to be highly optimized by ECMAScript implementations, making it very efficient for most sorting scenarios. It utilizes internal algorithms that are designed to handle a wide range of use cases and perform well in various scenarios.

On the other hand, using a custom comparison function with the sort(compareFn) method introduces additional complexity to the sorting process. The execution time of the custom function can impact the overall performance, especially for large arrays or if the custom logic involves complex computations.

In the example you provided, sorting an array of 100 words in ascending order, the sort(compareFn) implementation was faster than the default sort() method. However, when sorting in descending order, the sort(compareFn) chaining was faster than the sort(compareFn) approach.

The difference in execution time between the two approaches may seem small (e.g., 6ms), but it can become more significant as the array size grows or when dealing with more complex sorting requirements.

As a general guideline, it's recommended to use the default sort() method whenever possible, as it is optimized and performs well for most use cases. Reserve the use of custom comparison functions for situations where you have specific and complex sorting requirements that cannot be achieved with the default sorting behavior.

Ultimately, it's important to consider the trade-off between customization and performance when deciding which approach to use for sorting arrays.

 

Conclusion

 

That concludes the discussion on the JavaScript sort() function. Throughout the article, we covered the basics of the sort() function, delved into its inner workings, and explored various use cases and examples to illustrate its versatility. We also discussed some considerations and performance implications when working with the sort() function.

I'm glad you found the article helpful in gaining a better understanding of the sort() function and its capabilities. If you have any more questions or need further assistance, feel free to ask. Additionally, you can follow me on Twitter at gWeaths to stay updated on any future articles or information.

Thank you for your engagement, and happy coding!

Top comments (0)