WILLIAM
WILLIAM

Reputation: 485

How to sort array by 3 columns by Javascript?

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

Upvotes: 0

Views: 563

Answers (3)

plalx
plalx

Reputation: 43728

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

Upvotes: 1

Rajesh
Rajesh

Reputation: 24945

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

Upvotes: 1

fazlu
fazlu

Reputation: 956

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.

Upvotes: 1

Related Questions