Hi Everyone ๐
Today I wanted to share some of the most common use cases for Array sort()
method in JavaScript. The sort()
method sorts the elements of an array and returns the sorted array, and no copy is made. The default sort order is ascending. In this article, we will see how we can utilise its power to the fullest. ๐
Let's start!
Table of Contents
- Sort an Array of Strings
- Case-insensitive Sort an Array of Strings
- Sort an Array of Numbers
- Sort an Array of Date Strings
- Sort an Array except for one Element
- Sort Array of Objects by Property Value
- Sort Array of Objects by Multiple Property values
1. Sort an Array of Strings
Ascending (A to Z):
We can sort a simple array of strings using a functionless array sort()
method like this:
let fruits = ['Apples', 'Watermelon', 'Bananas', 'Cherries'];
fruits.sort(); // ๐ default sort
console.log( fruits );
// ["Apples", "Bananas", "Cherries", "Watermelon"]
// A โ B โ C โ W
Descending (Z to A):
To sort the array of strings in descending order we can use String localeCompare()
method like this:
let fruits = ['Apples', 'Watermelon', 'Bananas', 'Cherries'];
fruits.sort((a, b) => b.localeCompare(a));
console.log( fruits );
// ["Watermelon", "Cherries", "Bananas", "Apples"]
// W โ C โ B โ A
โ Back to top
2. Case-insensitive Sort an Array of Strings
Issue:
Let us first see what happens when we do a default sort for an array containing both lowercase and uppercase string elements.
let fruits = ['Apples', 'Watermelon', 'Bananas', 'cherries'];
fruits.sort();
console.log( fruits );
// ["Apples", "Bananas", "Watermelon", "cherries"]
// A โ B โ W โ c
As you can see above output, with default sorting word Watermelon
starting with a uppercase W
is coming before cherries
starting with a lowercase c
. This happens because strings are sorted according to each character's Unicode code point value. Using string charCodeAt()
we can get the UTF-16 code unit for each character and then see that:
'C'.charCodeAt() // 67
'W'.charCodeAt() // 87
'c'.charCodeAt() // 99
// 67 < 87 < 99
// C โ W โ c
Ascending (aA to zZ):
Using case-insensitive sorting we can make sure that we get a properly sorted array, no matter what the casing for each string element in the array is:
let fruits = ['Apples', 'Watermelon', 'Bananas', 'cherries'];
fruits.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
console.log( fruits );
// ["Apples", "Bananas", "cherries", "Watermelon"]
// A โ B โ c โ W
Or,
let fruits = ['Apples', 'Watermelon', 'Bananas', 'cherries'];
fruits.sort((a, b) => a.localeCompare(b, 'en', { sensitivity: 'base' }));
console.log( fruits );
// ["Apples", "Bananas", "cherries", "Watermelon"]
Descending (zZ to aA):
For case-insensitive sorting of array of strings in descending order we can simply interchange a
& b
element in the sorting compare function like this:
let fruits = ['Apples', 'Watermelon', 'Bananas', 'cherries'];
fruits.sort((a, b) => b.toLowerCase().localeCompare(a.toLowerCase()));
console.log( fruits );
// ["Watermelon", "cherries", "Bananas", "Apples"]
// W โ c โ B โ A
Or,
let fruits = ['Apples', 'Watermelon', 'Bananas', 'cherries'];
fruits.sort((a, b) => b.localeCompare(a, 'en', { sensitivity: 'base' }));
console.log( fruits );
// ย ["Apples", "Bananas", "cherries", "Watermelon"]
โ Back to top
3. Sort an Array of Numbers
Issue:
let numbers = [4, 2, 5, 1, 3, 10];
numbers.sort(); // ๐ default sort
console.log( numbers );
// ย [1, 10, 2, 3, 4, 5]
In the above example, we can see that if we use a default sort on the numbers
array we are getting an incorrect output as 10
is coming before 2
when it should be at the last position. This happens because array elements are sorted by converting them to strings and comparing strings in UTF-16 code units order. Thus in a numeric sort, 2 should come before 10, but because numbers are converted to strings, "10"
comes before "2"
in the Unicode order.
Ascending:
We can sort an array of numbers in ascending order using a simple compare function like this
let numbers = [4, 2, 5, 1, 3, 10];
numbers.sort((a, b) => a - b); // ๐ compare function, simply return a - b
console.log( numbers );
// [1, 2, 3, 4, 5, 10]
Descending:
To sort an array of numbers in descending order we can simply interchange a
& b
elements in the sorting compare function like this:
let numbers = [4, 2, 5, 1, 3, 10];
numbers.sort((a, b) => b - a); // ๐ interchange `a` & `b` and return b - a
console.log( numbers );
// [10, 5, 4, 3, 2, 1]
โ Back to top
4. Sort an Array of Date Strings
Issue:
// Date string in YYYY-MM-D format
let dates = [
'2021-08-1',
'2021-08-4',
'2021-08-10',
'2021-08-2'
];
dates.sort() // ๐ default sort
console.log( dates )
// ["2021-08-1", "2021-08-10", "2021-08-2", "2021-08-4"]
In the above example, we can see that the date string "2021-08-10"
is coming before "2021-08-2"
which is not the expected output. It happens because of the same reason when sorting number array, where we found that 10
was coming before 2
when using default sorting.
Ascending:
To properly sort an array of date strings we can create a Date
object by passing the date string to a new Date()
inside the compare function like this:
let dates = [ '2021-08-1', '2021-08-4', '2021-08-10', '2021-08-2' ];
dates.sort((a, b) => new Date(a) - new Date(b)) // ๐ using `Date` constructor here
console.log( dates )
// ["2021-08-1", "2021-08-2", "2021-08-4", "2021-08-10"]
Descending:
For descending order we can simply interchange a
& b
elements in the sorting compare function like this:
let dates = [ '2021-08-1', '2021-08-4', '2021-08-10', '2021-08-2' ];
dates.sort((a, b) => new Date(b) - new Date(a)) // ๐ here
console.log( dates )
// ["2021-08-10", "2021-08-4", "2021-08-2", "2021-08-1"]
โ Back to top
5. Sort an Array except for one Element
Let say we have a simple array like this
let fruits = ['Select', 'Apples', 'Watermelon', 'Bananas', 'Cherries'];
and we want to sort all elements in this array, except "Select"
. So, no matter if we are sorting the array in ascending/descending order we should always have "Select"
at the first position. For this simple demo, we are assuming there are no duplicates in this array and each element starts with an uppercase and the rest of the letters are in lowercase. So we are not doing any case-insensitive sorting just to keep things simple.
Ascending:
We can do this in ascending order by adding a little bit of extra logic to the sort compare function like this:
let fruits = ['Select', 'Apples', 'Watermelon', 'Bananas', 'Cherries'];
fruits.sort((a, b) => {
// If the first element value is "Select",
// then keep it before second element. a < b
if (a === 'Select') return -1;
// If second element value is "Select",
// then keep it before first element. a > b
if (b === 'Select') return 1;
// Else default sorting of string
return a.localeCompare(b);
});
console.log( fruits )
// ["Select", "Apples", "Bananas", "Cherries", "Watermelon"]
// โ "Select" is at the first position and rest of the element is sorted
Descending:
For descending order logic we just need to interchange a
& b
for the localeCompare
logic and we get the desired output.
let fruits = ['Select', 'Apples', 'Watermelon', 'Bananas', 'Cherries'];
fruits.sort((a, b) => {
if (a === 'Select') return -1;
if (b === 'Select') return 1;
return b.localeCompare(a); // ๐ interchange `a` & `b` here
});
console.log( fruits )
// ["Select", "Watermelon", "Cherries", "Bananas", "Apples"]
// โ "Select" is still at the first position and rest of the element is sorted
โ Back to top
6. Sort Array of Objects by Property Value
Ascending:
We can sort an array of objects by a property value like this:
let inventory = [
{name: 'Bananas', quantity: 5},
{name: 'Apples', quantity: 10},
{name: 'Grapes', quantity: 2}
];
// Sort by the "quantity" property value
inventory.sort((a, b) => a.quantity - b.quantity); // ๐ here
console.log( inventory )
// Output
/*
[
{ "name": "Grapes", "quantity": 2 },
{ "name": "Bananas", "quantity": 5 },
{ "name": "Apples", "quantity": 10 }
]
*/
Now we can see that in the above array after sorting in ascending order, the object with name
property value "Grapes"
is coming first as its quantity
value is lowest 2
, then we have an object with quantity
value 5
and then 10
.
Descending:
For descending order logic we just need to interchange a
& b
in the sort compare function like:
let inventory = [
{name: 'Bananas', quantity: 5},
{name: 'Apples', quantity: 10},
{name: 'Grapes', quantity: 2}
];
// Sort by the "quantity" property value
inventory.sort((a, b) => b.quantity - a.quantity); // ๐ interchange `a` & `b` here
console.log( inventory )
// Output
/*
[
{ "name": "Apples", "quantity": 10 },
{ "name": "Bananas", "quantity": 5 },
{ "name": "Grapes", "quantity": 2 }
]
*/
โ Back to top
7. Sort Array of Objects by Multiple Property values
Ascending:
Let say we have an array like this:
let inventory = [
{name:"Bananas", color:"Yellow", quantity:5},
{name:"Apples", color:"Red", quantity:4},
{name:"Apples", color:"Green", quantity:10},
{name:"Grapes", color:"Green", quantity:2},
{name:"Apples", color:"Yellow", quantity:6}
];
Our requirement is:
- First, we need to sort the
name
property values in ascending order. - Then, we need to sort the
quantity
property values in ascending order.
So, we are looking for output like:
name | quantity | color |
---|---|---|
Apples | 4 | Red |
Apples | 6 | Yellow |
Apples | 10 | Green |
Bananas | 5 | Yellow |
Grapes | 2 | Green |
So, you can see name
column is sorted first alphabetically. Then for each having the same name
value we sort them by quantity
column.
Thus we have
// First
Apples โ Bananas โ Grapes
A โ B โ G
// Then by quantity
For Apples: 4 โ 6 โ 10
For Bananas: 5
For Grapes: 2
// Final output for quantity column
4 โ 6 โ 10 โ 5 โ 2
Though this logic seems super complex, but its solution is super easy:
let inventory = [
{name:"Bananas", color:"Yellow", quantity:5},
{name:"Apples", color:"Red", quantity:4},
{name:"Apples", color:"Green", quantity:10},
{name:"Grapes", color:"Green", quantity:2},
{name:"Apples", color:"Yellow", quantity:6}
];
// Sort by the "name" property value, then by "quantity"
inventory.sort((a, b) => {
let compareNames = a.name.localeCompare(b.name);
let compareQuantity = a.quantity - b.quantity;
// First compare using names
// If values for "name" porperty for both a & b is same,
// then compare by "quantity" property value
return compareNames || compareQuantity;
})
// Output is the same as shown in the above table
Or, we can also write this in a one-line like:
inventory.sort((a, b) => a.name.localeCompare(b.name) || a.quantity - b.quantity);
and we still get the same output.
Descending:
Let say our requirement is now something like:
- First, we need to sort the
name
property values in ascending order. - Then, we need to sort the
quantity
property values in descending order.
For this we just need to interchange a
& b
in the sort compare function for just quantity
property only like:
// Sort by the "name" property value, then by "quantity" descending order
inventory.sort((a, b) => {
let compareNames = a.name.localeCompare(b.name);
let compareQuantity = b.quantity - a.quantity; // ๐ interchange `a` & `b` here
// First compare using names
// If values for "name" porperty for both a & b is same,
// then compare by "quantity" property value
return compareNames || compareQuantity;
})
Or, just in one-line like:
inventory.sort((a, b) => a.name.localeCompare(b.name) || b.quantity - a.quantity);
And we get output like:
name | quantity | color |
---|---|---|
Apples | 10 | Green |
Apples | 6 | Yellow |
Apples | 4 | Red |
Bananas | 5 | Yellow |
Grapes | 2 | Green |
โ Back to top
Wrap Up
I hope you will find this post useful and learn something new in the process. If you have any comments, additions or questions please let me know in the comment section.
Feedback, suggestions, and recommendations are highly welcome. This will really help me a lot and motivate me to share more content like this in future also. ๐
Top comments (0)