Basic and advance Array sorting with JavaScript
Tags: javascript, webdev, beginners, productivity
Published: 2023-04-27 21:15:56

## Basic

Sort an array by one value is relatively simple because a compare function passed to [array sort](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#description) follows this rule to apply the sorting order based on:

| Return value | Sorting order                           |
| ------------ | --------------------------------------- |
| Negative     | less (sort `a` before `z`)              |
| Zero	       | equal (keep original order `a` and `z`) |
| Positive     | greater (sort `z` before `a`)           |

Taking that in mind there are different approach to take depending of the data type.

### String

You can use `.sort()` without parameters to order strings, but is recommended to use [localeCompare](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare) because it can be configured to ignore punctuation (accents), returns `-1`, `0`, `1` if `a < z`, `a == z`, `a > z`.

```js
const animals = [ 'cat', 'dog', 'wolf', 'lion', 'sheep', 'antelope']
animals.sort((a, z) => a.localeCompare(z))
console.log(animals) // [ 'antelope', 'cat', 'dog', 'lion', 'sheep', 'wolf' ]
```

### Numeric

Subtraction works on numeric fields, because `a - z` gives `-`, `0`, `+` if `a < z`, `a == z`, `a > z`.

```js
let numbers = [ 0, 20, 2, 3, 30, 10, 1 ]
numbers.sort((a, z) => a - z)
console.log(numbers) //[ 0, 1, 2, 3, 10, 20, 30 ]
```

### Date 

Date (with or without time) compares with subtraction because date math converts to milliseconds since 1970.

```js
const dates = ['Mar 18 2016', '09/24/2017', 'Jan 22 2022', '1998-05-21']
dates.sort((a, z) => new Date(a) - new Date(z))
console.log(dates) // [ '1998-05-21', 'Mar 18 2016', '09/24/2017', 'Jan 22 2022' ]
```

### Boolean

Boolean compare with subtraction, which is guaranteed to turn `true` and `false` to `1` and `0` (therefore the subtraction produces `-1` or `0` or `1`).

```js
const boolean = [true, false, true, false, true]
boolean.sort((a, z) => Boolean(a) - Boolean(z))
console.log(Boolean) //[ false, false, true, true, true ]
```

> Drawing attention with the `Boolean()` constructor, even if they're already Boolean.

### Reverse Order

Swapping the comparison values

```js
animals.sort((a, z) => z.localeCompare(a))
numbers.sort((a, z) => z - a)
dates.sort((a, z) => new Date(z) - new Date(a))
boolean.sort((a, z) => Boolean(z) - Boolean(a))
```

Or negate the comparison 

```js
animals.sort((a, z) => -( a.localeCompare(z) ))
numbers.sort((a, z) => -( a - z ))
dates.sort((a, z) => -( new Date(a) - new Date(z) ))
boolean.sort((a, z) => -( Boolean(a) - Boolean(z) ))
```

> 💡 take in mind this negate trick because it can be useful later for advance sorting

### Shuffle

Sometimes we need to shuffle or unsort an array, for example on a playlist or choosing a winner. No matters the type we can use the same.

```js
animals.sort(() => Math.random() - 0.5)
numbers.sort(() => Math.random() - 0.5)
dates.sort(() => Math.random() - 0.5)
boolean.sort(() => Math.random() - 0.5)
```

`Math.random()` returns a value between `0` and `<1`, then gives `-`, `0`, `+` if `< 0.5`, `= 0.5`, `> 0.5`.

---

## Advanced

To sort an array of objects we are going to use all the previous examples, but if we need to made sorting using multiple properties, we are going to need some special tricks.

```js
const records = [
  {
    id: '1',
    country: 'Colombia',
    value: 500,
    hasDetail: true,
    timestamp: '2023-04-27T02:23:39.000Z'
  },
  {
    id: '2',
    country: 'Spain',
    value: 1_000,
    hasDetail: true,
    timestamp: '2015-04-27T23:31:05.000Z'
  },
  {
    id: '3',
    country: 'Argentina',
    value: 1_000,
    hasDetail: false,
    timestamp: '2000-01-01T00:00:00.000Z'
  },
    {
    id: '5',
    country: 'Colombia',
    value: 2_000,
    hasDetail: true,
    timestamp: '2023-04-27T02:23:39.000Z'
  },
  {
    id: '6',
    country: 'Spain',
    value: 1_000,
    hasDetail: false,
    timestamp: '2018-04-27T23:31:05.000Z'
  },
  {
    id: '4',
    country: 'Argentina',
    value: 100,
    hasDetail: true,
    timestamp: '2020-01-01T23:15:00.000Z'
  }
]
```

This raw data (without sorting) using `console.table(records)` will show:

| id  |   country   | value | hasDetail |         timestamp          |
| :-- | :---------: | ----: | :-------: | :------------------------- |
| '1' | 'Colombia'  |  500  |   true    | '2023-04-27T02:23:39.000Z' |
| '2' |   'Spain'   | 1000  |   true    | '2015-04-27T23:31:05.000Z' |
| '3' | 'Argentina' | 1000  |   false   | '2000-01-01T00:00:00.000Z' |
| '5' | 'Colombia'  | 2000  |   true    | '2023-04-27T02:23:39.000Z' |
| '6' |   'Spain'   | 1000  |   false   | '2018-04-27T23:31:05.000Z' |
| '4' | 'Argentina' |  100  |   true    | '2020-01-01T23:15:00.000Z' |

First, we need to create a sort object with each property.

```js
records.sort((a, z) => {
  const sort = {
    id: a.id.localeCompare(z.id), //string
    country: a.country.localeCompare(z.country), //string
    value: a.value - z.value, //numeric
    hasDetail: Boolean(a.hasDetail) - Boolean(z.hasDetail), //boolean
    timestamp: new Date(a.timestamp) - new Date(z.timestamp) //date
  }
  ...
})
```

Then return the order according to your needs using the `||` operator, taking in mind that it follows the priority from left to right and, to reverse order use the **negate trick** in any field.

```js
records.sort((a, z) => {
  ...
  return sort.country || -sort.value || sort.timestamp
})
```

This means we want to sort by country ascending, then by value descending and then by timestamp ascending. The result will be:

| id  |   🔼country | 🔽value  | hasDetail |         🔼timestamp         |
| :-- | :---------: | ----: | :-------: | :------------------------- |
| '3' | 'Argentina' | 1000  |   false   | '2000-01-01T00:00:00.000Z' |
| '4' | 'Argentina' |  100  |   true    | '2020-01-01T23:15:00.000Z' |
| '5' | 'Colombia'  | 2000  |   true    | '2023-04-27T02:23:39.000Z' |
| '1' | 'Colombia'  |  500  |   true    | '2023-04-27T02:23:39.000Z' |
| '2' |   'Spain'   | 1000  |   true    | '2015-04-27T23:31:05.000Z' |
| '6' |   'Spain'   | 1000  |   false   | '2018-04-27T23:31:05.000Z' |

> **Note:** [`.sort()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort) mutes the array, [`.toSorted()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/toSorted) do the same but returns a new array with the elements sorted.

---

## Bonus

These array sorting methods are available as snippets on the [Arrow Functions Snippets](https://marketplace.visualstudio.com/items?itemName=deinsoftware.arrow-function-snippets) extension for VSCode.

[![Arrow Function Snippets](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r0pfio7l7s2nd4iv4hoo.png)](https://marketplace.visualstudio.com/items?itemName=deinsoftware.arrow-function-snippets)

---

**That’s All Folks!
Happy Coding** 🖖

[![beer](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mkgsx4aw6qn9i9ax6as9.png)](https://github.com/sponsors/deinsoftware)