Reputation: 537
I've created a util function to sort an array of objects in either ascending or descending order which accepts the property. It appears to work fine for sorting numeric, but not string properties. E.g. in the below, if you pass in "age" as the second argument it order correctly, however if you pass in "job" as the second argument, nothing happens. I was hoping it would order alphabetically by job (Engineer, Marketing, Sales). Any ideas how to fix this / why it is happening?
const arrayOfObjects = [
{ firstName: 'Joe', job: 'Engineer', age: 22 },
{ firstName: 'Sam', job: 'Sales', age: 30 },
{ firstName: 'Claire', job: 'Engineer', age: 40 },
{ firstName: 'John', job: 'Marketing', age: 29 },
{ firstName: 'Susan', job: 'Engineer', age: 21 },
];
const orderByValue = (array, orderByItem, order) => array.sort((a, b) => {
if (order === 'descending') {
return b[orderByItem] - a[orderByItem];
} else {
return a[orderByItem] - b[orderByItem];
}
});
// console.log('order by age:', orderByValue(arrayOfObjects, 'age'));
console.log('order by job:', orderByValue(arrayOfObjects, 'job'));
Upvotes: 0
Views: 51
Reputation: 5055
You can just use LocaleCompare
, and use the Numeric option to handle the numbers as well
LocaleCompare is a String method, so to handle Number types correctly you convert them using .toString()
, a[orderByItem] + ''
, or String(a[orderByItem])
const arrayOfObjects = [
{ firstName: 'Joe', job: 'Engineer', age: 22 },
{ firstName: 'Sam', job: 'Sales', age: 30 },
{ firstName: 'Claire', job: 'Engineer', age: 40 },
{ firstName: 'John', job: 'Marketing', age: 29 },
{ firstName: 'Susan', job: 'Engineer', age: 21 },
];
const orderByProperty = (array, orderByItem, order) => array.sort((a, b) => {
if (order === 'descending') {
return b[orderByItem].toString().localeCompare(a[orderByItem].toString(), 'en', {numeric: true});
} else {
return a[orderByItem].toString().localeCompare(b[orderByItem].toString(), 'en', {numeric: true});
}
});
console.log('order by age:', orderByProperty(arrayOfObjects, 'age'));
console.log('order by job:', orderByProperty(arrayOfObjects, 'job'));
.as-console-wrapper {max-height: 100% !important; top: 0;}
Upvotes: 4
Reputation: 386620
You could return a function as callback and omit for each comparison a check for order.
This approach uses simply greater/smaller operators, which works for strings as well.
const arrayOfObjects = [
{ firstName: 'Joe', job: 'Engineer', age: 22 },
{ firstName: 'Sam', job: 'Sales', age: 30 },
{ firstName: 'Claire', job: 'Engineer', age: 40 },
{ firstName: 'John', job: 'Marketing', age: 29 },
{ firstName: 'Susan', job: 'Engineer', age: 21 },
];
const orderByProperty = (array, orderByItem, order) => array.sort(order === 'descending'
? (a, b) => b[orderByItem] > a[orderByItem] || -(b[orderByItem] < a[orderByItem])
: (a, b) => a[orderByItem] > b[orderByItem] || -(a[orderByItem] < b[orderByItem])
);
console.log('order by age:', orderByProperty(arrayOfObjects, 'age'));
console.log('order by job:', orderByProperty(arrayOfObjects, 'job'));
.as-console-wrapper { max-height: 100% !important; top: 0; }
Upvotes: 1