Explain Codes LogoExplain Codes Logo

How to sort an array of objects by multiple fields?

javascript
functions
callbacks
promises
Anton ShumikhinbyAnton Shumikhin·Dec 14, 2024
TLDR
// Sorting: First by city (Cinderella, your carriage is ready) then by price (cheaper gets to the ball first) const sortedArray = yourArray.sort((a, b) => a.city.localeCompare(b.city) || b.price - a.price );

This solution sorts your "carriages" (objects) by "city" (field 1), then by the "fairest price" (field 2). It leverages ES6 syntax for efficiency in chaining comparison, demonstrating how to mix and mingle text and numeric sorts with grace.

Step-by-step: Create a multi-field sorting function

Sometimes, you need a customizable and reusable comparison function. Fear not, ES6 and a dash of imagination will render this task simpler than chanting "Bibbidi-Bobbidi-Boo"!

Dynamic sorting with arrow functions

Configure your sorting fields with direction, then feed these into your magic comparator function.

const sortBy = [ { field: "city", order: "asc" }, { field: "price", order: "desc" } ]; const sorcerySort = (fields) => { return (a, b) => { // Loop through each sorting condition for (let { field, order } of fields) { if (a[field] !== b[field]) { // If equal, move to the next condition return order === "asc" ? a[field].localeCompare(b[field]) : b[field].localeCompare(a[field]); } } return 0; // If all conditions match, they are equal }; }; const sortedArray = yourArray.sort(sorcerySort(sortBy));

Sorting with functional programming and immutability

In this potion, we mix the power of map for immutability with chained sorting—providing clean and reusable brewing.

const sortedArray = yourArray.map(objects => ({...objects})) .sort((a, b) => a.city.localeCompare(b.city) || b.price - a.price);

Source the magic: using libraries for sorting

The thenBy.js library casts a simplifying spell over multi-field sorting; perfect for the more complex enchantments.

const firstBy = require('thenby'); const sortedArray = yourArray.sort( firstBy('city').thenBy('price', -1) );

Magic touch to date and boolean

When dealing with date or boolean fields, ensure your function knows to treat them properly.

// Ensure older dates (more experienced wizards) appear first, then prioritize who is active (because magic) const sortedArray = yourArray.sort((a, b) => new Date(b.date) - new Date(a.date) || a.isActive - b.isActive );

Beware of performance

More comparisons mean more time. Do some preprocessing for excellent performance, especially when dealing with massive arrays (Hagrid's creatures, anyone?).

yourArray.forEach(object => object.trueDate = new Date(object.date)); const sortedArray = yourArray.sort((a, b) => a.trueDate - b.trueDate || a.isActive - b.isActive );

Pulling rabbits out of hats: Edge cases

Type consistency in fields

Ensure each field has consistent types, otherwise, your magic could backfire and results might not be as expected.

Magical disappearance: nulls and undefined values

Fields might be null or undefined, so add an extra protection spell to your sort function:

// When city is undefined or null, defaults to an empty string, and price to 0 - because magic! const sortedArray = yourArray.sort((a, b) => (a.price || "") .localeCompare(b.price || "") || (b.city || 0) - (a.city || 0) );

Future proof casting

Design your functions with the eye of foresight. Making it modular ensures it handles future use cases with ease - much like a well-crafted charm.

References