0

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'));
3
  • 2
    strings aren't numbers, what do you expect - to do for strings? Commented Jan 6, 2020 at 16:39
  • How do you "subtract" two strings? Commented Jan 6, 2020 at 16:39
  • I tried using a[orderByItem] > b[orderByItem] but doesn't work either. Commented Jan 6, 2020 at 16:41

2 Answers 2

4

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;}

Sign up to request clarification or add additional context in comments.

4 Comments

Thanks! I see, so my above example only works with numbers! To work for just string values I'd do: console.log(arrayOfObjects.sort((a, b) => a.job.localeCompare(b.job))); Then to use both string and number I'd do what @Light did above.
Yeah; LocaleCompare is for Strings primarily, and then the Numeric options does numbers as well
Doesn't this throw a syntax error for numbers? Number.localeCompare() is not a function.
It does ( did ) - You can use .toString() or '' + a[orderByItem] to convert to a String before hand; Thanks for pointing that out so I could fix it though
1

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; }

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.