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
ofa
withb
(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 theprop
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.