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
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));
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();
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();
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 }
];
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;
Top comments (1)
Ooh, I never thought of utilizing
toString
when sorting! Great tips!