Top 7 JavaScript Array sort() Method Use Cases
Tags: javascript, beginners, webdev, productivity
Published: 2021-09-02 08:10:27

Hi Everyone 👋

Today I wanted to share some of the most common use cases for Array [`sort()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/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!
<hr>

### Table of Contents <a name="go-to-top"></a>

- [Sort an Array of Strings](#chapter-1)
- [Case-insensitive Sort an Array of Strings](#chapter-2)
- [Sort an Array of Numbers](#chapter-3)
- [Sort an Array of Date Strings](#chapter-4)
- [Sort an Array except for one Element](#chapter-5)
- [Sort Array of Objects by Property Value](#chapter-6)
- [Sort Array of Objects by Multiple Property values](#chapter-7)

<hr>

### 1. Sort an Array of Strings <a name="chapter-1"></a>

#### Ascending (A to Z):

We can sort a simple array of strings using a functionless array `sort()` method like this:

```js
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()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare) method like this:

```js
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](#go-to-top)

<hr>

### 2. Case-insensitive Sort an Array of Strings <a name="chapter-2"></a>

#### Issue:

Let us first see what happens when we do a default sort for an array containing both lowercase and uppercase string elements. 

```js
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()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/charCodeAt) we can get the UTF-16 code unit for each character and then see that:

```js
'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:

```js
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,

```js
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:

```js
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,

```js
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](#go-to-top)

<hr>

### 3. Sort an Array of Numbers <a name="chapter-3"></a>

#### Issue:

```js
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

```js
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:

```js
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](#go-to-top)

<hr>

### 4. Sort an Array of Date Strings <a name="chapter-4"></a>

#### Issue:

```js
// 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:

```js
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:

```js
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](#go-to-top)

<hr>

### 5. Sort an Array except for one Element <a name="chapter-5"></a>

Let say we have a simple array like this

```js
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:

```js
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.

```js
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](#go-to-top)

<hr>

### 6. Sort Array of Objects by Property Value <a name="chapter-6"></a>

#### Ascending:

We can sort an array of objects by a property value like this:

```js
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:

```js
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](#go-to-top)

<hr>

### 7. Sort Array of Objects by Multiple Property values <a name="chapter-7"></a>

#### Ascending:

Let say we have an array like this:

```js
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:

1. First, we need to sort the `name` property values in ascending order.
2. 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 

```js
// 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:

```js
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:

```js
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:

1. First, we need to sort the `name` property values in ascending order.
2. 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:

```js
// 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:

```js
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](#go-to-top)

<hr>

### 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. 😀

#### Happy Coding!