3 Neat Tricks For Sorting Arrays of Objects in JavaScript
Tags: javascript, codenewbie
Published: 2021-10-12 22:45:03

Working with arrays of objects in JavaScript can be a headache. [Comparing arrays of objects](https://masteringjs.io/tutorials/fundamentals/compare-arrays) is tricky without libraries. But, thankfully, [sorting arrays of objects](https://masteringjs.io/tutorials/fundamentals/sort-array-of-objects) is somewhat easier because of some neat tricks.

## 1) Sorting By Date Properties

The hard part of sorting arrays of objects is to compare objects _without_ transforming them explicitly. If you transform an array using `map()` or [`filter()`](https://masteringjs.io/tutorials/fundamentals/filter) before sorting, you lose the original array.

Sorting by date properties is a convenient one-liner because [comparing dates in JavaScript](https://masteringjs.io/tutorials/fundamentals/compare-dates) is easy: subtracting 2 dates returns the difference between the two dates in milliseconds.

```javascript
const d1 = new Date('2019-06-01');
const d2 = new Date('2018-06-01');
const d3 = new Date('2019-06-01');

d1 - d3; // 0
d1 - d2; // 31536000000
```

So if you want to sort by a `createdAt` property, all you need to do is subtract the values of `createdAt` in the `sort()` [callback](https://masteringjs.io/tutorials/fundamentals/callbacks).

```javascript
const d1 = new Date('2019-06-01');
const d2 = new Date('2018-06-01');
const d3 = new Date('2019-06-01');

const objects = [
  { createdAt: d1, name: 'Test 1' },
  { createdAt: d2, name: 'Test 2' },
  { createdAt: d3, name: 'Test 3' }
];

objects.sort((a, b) => a.createdAt - b.createdAt);

// [ 'Test 2', 'Test 1', 'Test 3' ]
console.log(objects.map(o => o.name));
```

## 2) Using String Conversions

This trick is a bit less useful, but still interesting. Remember that [JavaScript converts the array elements to strings before sorting](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort) _unless_ you pass a function parameter to `sort()`. That means you can define a custom [`toString()` function](https://masteringjs.io/tutorials/fundamentals/tostring) and JavaScript will sort objects by that `toString()` function as shown below.

```javascript
class User {
  constructor(name) {
    this.name = name;
  }

  toString() {
    return this.name.length;
  }
}

const arr = [
  new User('333'),
  new User('4444'),
  new User('22')
];

// Sorts users by `name.length`!
// [ Test { name: '22' }, Test { name: '333' }, Test { name: '4444' } ]
arr.sort();
```

This approach is limited because you can only define one `toString()` function for a given class. And, if you want to change the sort order, you need to change each object's `toString()` function.

But this approach can be very useful if your object's `toString()` function is exactly what you want to sort by.

```javascript
class User {
  constructor(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
  }

  toString() {
    return `${this.lastName}, ${this.firstName}`;
  }
}

const arr = [
  new User('John', 'Smith'),
  new User('Bill', 'Jones'),
  new User('Mike', 'Palmer')
];

// Sort users by "last, first"
arr.sort();
```

## 3) Sorting by Arbitrary Orderings

Suppose you have an array of characters from _Star Trek: The Next Generation_:

```javascript
const characters = [
  { firstName: 'Jean-Luc', lastName: 'Picard', rank: 'Captain', age: 59 },
  { firstName: 'Will', lastName: 'Riker', rank: 'Commander', age: 29 },
  { firstName: 'Geordi', lastName: 'La Forge', rank: 'Lieutenant', age: 29 }
];
```

Sorting by name or age is easy. But what about sorting by `rank`? Turns out that's easy too. Create a map from ranks to numbers, and sort by the difference in ranks as shown below.

```javascript
const rankOrder = new Map([
  ['Captain', 1],
  ['Commander', 2],
  ['Lieutenant', 3]
]);

characters.sort((a, b) => {
  return rankOrder.get(a.rank) - rankOrder.get(b.rank);
});

// Picard, Riker, La Forge
characters;
```