0

I am trying to sort array by three columns. Below is my sample array. Sometime, the column can be null too, so I do a checking in my sort function. However, now I would like to sort the name first and then salary and then bonus. How can I achieve that?

let employees = [
    {name: 'John', salary: 90000, bonus: 1000},
    {name: 'David', salary: 90000, bonus: 1200},
    {name: 'Ana', salary: 80000, bonus: 3000}
];

// Code for sorting salary first and then bonus:
function sort(a,b) {
  if (a.salary=== null && b.salary=== null ){
    return a.bonus- b.bonus;
  } 
  else if (a.salary!== null && b.salary=== null ){
    return -1;
  }
  else if (a.salary=== null && b.salary!== null){
    return 1;
  }else if (a.salary!== null && b.salary!== null){
    return a.salary- b.salary;
  }
  else {
    return 1;
  }
}

employees.sort(sort);
console.log(employees);

1
  • Just return the first non-zero compare or the last value. Commented May 20, 2020 at 3:20

3 Answers 3

1

Just return the first non-zero compare value. I've also made sure anything that's not a number would be sorted last, but if you are certain that you will only get a valid number or null then you can simplify the checks.

const employees = [
    {name: 'Ana', salary: null, bonus: 3000},
    {name: 'Ana', salary: 80000, bonus: 3000},
    {name: 'Ana', salary: 70000, bonus: 3000},
    {name: 'Ana', salary: 70000, bonus: 1000}
];

employees.sort((a, b) => {
  return a.name.localeCompare(b.name) ||
    safeNumCompare(a.salary, b.salary) ||
    safeNumCompare(a.bonus, b.bonus);
});

console.log(employees);

function safeNumCompare(a, b) {
  const aValid = isValidNum(a), bValid = isValidNum(b);

  if (!(aValid || bValid)) return 0;
  if (!aValid) return 1;
  if (!bValid) return -1;
  return a - b;
}

function isValidNum(num) {
  return typeof num === 'number' && !isNaN(num);
}

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

1 Comment

When dealing with strings, use string.localeCompare. Its more safe and does your comparison
1

There is an npm package called lodash. You can achieve your required functionality with their sortBy method.

const _ = require('lodash');

let employees = [
    {name: 'John', salary: 90000, bonus: 1000},
    {name: 'David', salary: 90000, bonus: 1200},
    {name: 'Ana', salary: 80000, bonus: 3000}
];

const sortedArray = _.sortBy(employees, ['name', 'salary', 'bonus']);

I hope it helps.

1 Comment

Its not ideal to assume and use a library. Better to check with OP
1

You can use this logic:

  • Sort needs to return a numeric value. So you can use arithmetic operations.
  • Your values can be null, so better to default.
    • 0 for ascending
    • Infinity for descending
  • Perform a - b operation for ascending.
  • For priority fall through, use || so that if first equation returns 0, it'll check for next priority

Note:

Above logic will sort in ascending of name then salary and then bonus. So if both users have same salary, then their bonus will be checked and sorted in that fashion.

let employees = [{ name: 'John', salary: 90000, bonus: 1000 }, { name: 'David', salary: 90000, bonus: 1200}, { name: 'David',  salary: null,  bonus: 1200}, {  name: 'Ana',  salary: 80000,  bonus: 3000}, {  name: 'Ana',  salary: 80000,  bonus: null }];

function sort(a, b) {
  return (a.name.localeCompare(b.name)) ||
    ((a.salary || Infinity) - (b.salary || Infinity)) ||
    ((a.bonus || 0) - (b.bonus || 0));
}

employees.sort(sort);
console.log(employees);

As rightly suggested by plalx

He wanted nulls sorted last though and by name first as well.

Hence using Infinity for defaulting salary

6 Comments

He wanted nulls sorted last though and by name first as well.
@plalx in that case I'll use your idea of INFINITY
Yeah I wanted to use Infinity, but 0 || Infinity === Infinity so in the end I went for a proper safe compare.
Note that the new implementation will sort 0 last because of the above comment. Just making sure you get the comment notification.
Thats a question for OP. Can a salary be 0? If yes, how is it different from null
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.