Bit Hacker Logo
Bit Hacker Logo
Sorting multiple object properties with JavaScript

Sorting multiple object properties with JavaScript

Sorting regular arrays in javascript is a piece of cake - even sorting by object properties is simple. But sometimes you may want to provide the ability to sort by multiple properties at the same time. Let's dive into the sort function to see how we can accomplish this.

How JavaScript .sort() works

Sort works by comparing two values to determine which is considered greater. For simple arrays this works by subtracting a from b:

var array = [12, 3, 5, 22]
array.sort(function(a,b){
  return a - b
})

The comparison looks at the subtracted values with the following logic:

Less than 0 a is sorted considered lower than b
0 a and b are considered equal
Greater than 0 b is considered lower than a

When introducing objects we can use the same logic, just by modifying the sort function slightly:

var array = [{number:12}, {number:3}, {number:5}, {number:22}]
array.sort(function(a,b){
  return a.number - b.number;
})

Sorting strings

For simple numeric values subtraction is fine but strings will need different logic. To do this, we can use the built in equality operators:

var array = [{fruit:'Tomato'}, {fruit:'Banana'}, {fruit:'Apple'}, {fruit:'Orange'}]
array.sort(function(a,b){
  return (a.fruit < b.fruit ? -1 : (a.fruit > b.fruit ? 1 : 0));
})

String vs numbers

At first glance our fruit sort seems to work with numbers as well. However this only works for single digit number values. To get around this we will detect if the property value is a string or a number and compare accordingly. This is achieved by checking if the value is Not a Number using the built in isNaN method.

array.sort(function(a,b){
  if( isNaN(a.fruit) && isNaN(b.fruit) ) {
    return (a.fruit < b.fruit ? -1 : (a.fruit > b.fruit ? 1 : 0));
  } else {
    return a.fruit - b.fruit
  }
})

Changing the direction

Say you now want to flip the sort order. Thanks to the sort logic we can multiple the subtracted values by -1 to reverse the value of a and b.

array.sort(function(a,b){
  let val = 0;
  if( isNaN(a.fruit) && isNaN(b.fruit) ) {
    val = (a.fruit < b.fruit ? -1 : (a.fruit > b.fruit ? 1 : 0));
  } else {
    val = a.fruit - b.fruit
  }
  return -1*val;
})

Deeper: The actual sort algorithm used is dependent on JavaScript implementation and will vary from platform to platform.

Sorting multiple properties at once

Sorting objects by a single property is great but we want a little more versatility. Let's take a look at these students and see if we can sort them by grade, then by last name.

let students = [{
	firstName: 'John',
	lastName: 'Appletree',
	grade: 12
},{
	firstName: 'Mighty',
	lastName: 'Peachtree',
	grade: 10
},{
	firstName: 'Kim',
	lastName: 'Appletree',
	grade: 11
},{
	firstName: 'Shooter',
	lastName: 'Appletree',
	grade: 12
}];

Selecting properties

To start, we will build an array of properties that we want to sort by along with the direction we want to sort. While we are specifying the properties we can also include a the direction.

let sortBy = [{
  prop:'grade',
  direction: -1
},{
  prop:'lastName',
  direction: 1
}];

We now need to expand our sort function to look at multiple properties.

array.sort(function(a,b){
  let i = 0, result = 0;
  while(i < sortBy.length && result === 0) {
    result = sortBy[i].direction*(a[ sortBy[i].prop ].toString() < b[ sortBy[i].prop ].toString() ? -1 : (a[ sortBy[i].prop ].toString() > b[ sortBy[i].prop ].toString() ? 1 : 0));
    i++;
  }
  return result;
})

There is some extra stuff going on here so lets break it down:

  • Loop through sortBy properties
  • Compare the prop of a with b (using our string compare above)
    • We have added a .toString() call here to ensure that numeric values are turned it to strings to make our compare more versatile
  • If result is 0 the prop values are the same continue to the next property
  • Multiply the result by the direction

Result

This will output our students in the following order:

[{
  firstName: 'John',
  lastName: 'Appletree',
  grade: 12
},{
  firstName: 'Shooter',
  lastName: 'Appletree',
  grade: 12
},{
  firstName: 'Kim',
  lastName: 'Appletree',
  grade: 11
},{
  firstName: 'Mighty',
  lastName: 'Peachtree',
  grade: 10
}]

That is it! You now have a method capable of sorting multiple properties with direction.