DEV Community

Mastering JS
Mastering JS

Posted on

3 Neat Tricks For Sorting Arrays of Objects in JavaScript

Working with arrays of objects in JavaScript can be a headache. Comparing arrays of objects is tricky without libraries. But, thankfully, sorting arrays 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() before sorting, you lose the original array.

Sorting by date properties is a convenient one-liner because comparing dates in JavaScript is easy: subtracting 2 dates returns the difference between the two dates in milliseconds.

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
Enter fullscreen mode Exit fullscreen mode

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.

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));
Enter fullscreen mode Exit fullscreen mode

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 unless you pass a function parameter to sort(). That means you can define a custom toString() function and JavaScript will sort objects by that toString() function as shown below.

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();
Enter fullscreen mode Exit fullscreen mode

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.

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();
Enter fullscreen mode Exit fullscreen mode

3) Sorting by Arbitrary Orderings

Suppose you have an array of characters from Star Trek: The Next Generation:

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 }
];
Enter fullscreen mode Exit fullscreen mode

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.

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;
Enter fullscreen mode Exit fullscreen mode

Top comments (1)

Collapse
 
lioness100 profile image
Lioness100

Ooh, I never thought of utilizing toString when sorting! Great tips!