Sorting arrays is pretty simple in JavaScript because we have the .sort()
method. If you have an array of strings, it's super easy to get values in order. Like this:
// in no particular order
let myArray = ["deer", "zebra", "ant", "crocodile", "beetle"];
// sort it
myArray.sort();
// now it's in order
console.log(myArray); // ["ant", "beetle", "crocodile", "deer", "zebra"]
But what if you have an array of objects?
Yep, .sort()
can handle that too! But, since objects can have various properties, you'll need to give it a compare function so it knows what value (or values) to sort by.
Let me show you an example.
Example array of objects
Here's my array of objects, the kind of array of objects you might get in a real-world scenario.
let people = [
{
id: 1,
name: {
first: "Jack",
last: "Smith"
},
age: 37
},
{
id: 2,
name: {
first: "Sandra",
last: "Jones"
},
age: 21
},
{
id: 3,
name: {
first: "Julie",
last: "Cooper"
},
age: 52
},
{
id: 4,
name: {
first: "Ben",
last: "Goldberg"
},
age: 19
},
{
id: 5,
name: {
first: "Lance",
last: "Heffernan"
},
age: 43
}
];
You'll notice this array is already in order. But maybe not the order we want. The objects are ordered by id
from 1 to 5. And that's great and all, but that id
property doesn't mean much to us when we display our data.
Instead, we might want to display our people in alphabetical order, or even by age. So let's do that next.
Ordering the array of objects by property value
To sort by property value, we can give .sort()
a compare function (compareFn
) that is called with two arguments, a
and b
.
// sort with a compare function
yourArray.sort(function(a, b) {
// return 1, -1 or 0;
});
// or as an arrow function
yourArray.sort((a, b) => {
// return 1, -1 or 0;
});
If you return a number greater than 0 from the compare function, it will sort a
after b
.
If you return a number less than 0 from the compare function, it will sort a
before b
.
And if you return 0, it will keep a
and b
in the original order.
For an array of objects, we will need to access the properties on a
and b
for sorting, like a.propertyName
, so the compare function you use will look something like this:
yourArray.sort((a, b) => {
if(a.key < b.key) {
return -1;
} else if (a.key > b.key) {
return 1
} else {
return 0;
}
});
// or if you wanted to one-liner it
// but I won't be doing this in the examples for readability
yourArray.sort((a, b) => a.key < b.key ? -1 : a.key > b.key ? 1 : 0);
Let's see it in action on our example people
array.
Sorting by name property (strings)
Imagine you are displaying this array as a list of contacts. You would usually show contacts in alphabetical order. So let's start by sorting our array alphabetically by name.
I'm going to go with the first name - but if you are old school, you can sort by the last name following the same system.
people.sort((a, b) => {
if (a.name.first < b.name.first) {
return -1;
} else if (a.name.first > b.name.first) {
return 1;
} else {
return 0;
}
});
console.log(people);
// [
// {
// "id": 4,
// "name": {
// "first": "Ben",
// "last": "Goldberg"
// },
// "age": 19
// },
// {
// "id": 1,
// "name": {
// "first": "Jack",
// "last": "Smith"
// },
// "age": 37
// },
// {
// "id": 3,
// "name": {
// "first": "Julie",
// "last": "Cooper"
// },
// "age": 52
// },
// {
// "id": 5,
// "name": {
// "first": "Lance",
// "last": "Heffernan"
// },
// "age": 43
// },
// {
// "id": 2,
// "name": {
// "first": "Sandra",
// "last": "Jones"
// },
// "age": 21
// }
// ]
Now our array is sorted alphabetically by first name! Ben, Jack, Julie, Lance, Sandra.
Ok, ok, there's a lot going on there, and if you are looking at that function thinking, WTF?! I don't blame you. So let's go through it and understand how it works.
For our array of objects, since a
and b
are objects, we are comparing the property values (e.g. a.name
), instead of comparing a
and b
, to tell .sort()
how to sort.
The name property is an object within the array of objects...
name: {
first: "Ben",
last: "Goldberg"
},
So to access the first name value, we use a.name.first
and b.name.first
.
When we check if a.name.first
is less than b.name.first
, the strings are compared alphabetically* and so we can say if the name in a
is less than the name in b
in the alphabet, a
should be sorted before b
, so we return -1
.
If it's after, then we return 1
to sort a
after b
instead. Otherwise, if they match, keep them in the same order (0
).
*It's not strictly alphabetical - it's Unicode - so uppercase and lowercase do matter here. For example "Ben" > "Andrew" === true
but "Ben" > "andrew" === false
. If this could be an issue in your data, you can normalise your strings when you compare by converting both to uppercase (or both to lowercase).
people.sort((a, b) => {
if (a.name.first.toUpperCase() < b.name.first.toUpperCase()) {
return -1;
} else if (a.name.first.toUpperCase() > b.name.first.toUpperCase()) {
return 1;
} else {
return 0;
}
});
If you want to switch things around and sort Z to A (instead of A to Z), you can return 1
if a
is less than b
, and -1
if it's more.
// sorting Z-A instead
people.sort((a, b) => {
if (a.name.first.toUpperCase() < b.name.first.toUpperCase()) {
return 1;
} else if (a.name.first.toUpperCase() > b.name.first.toUpperCase()) {
return -1;
} else {
return 0;
}
});
Sorting by age property (numbers)
Ok, now we want to sort our people by age.
You can use the same method as above if you like. But do make sure you compare numbers - since by default sort()
compares them as strings. And while "1"
is less than "2"
, "10"
is less than "2"
too - eek!
There's a better way to sort numbers with .sort()
.
Since age is a number, we can use a nice little trick to sort an ascending order. We can subtract b
from a
.
// sorting numbers
yourArray.sort((a, b) => {
return a - b;
});
This shortcut works with number values because if the number in b
is greater than a
, by subtracting b
from a
, we get a value less than 0.
For example if a
was 5 and b
was 7, that would return a result of -2. Since -2 is less than 0, a
will be sorted before b
.
And if a
is higher than b
, the value will be larger than 0, so a
will move after b
.
people.sort((a, b) => a.age - b.age);
console.log(people);
// [
// {
// "id": 4,
// "name": {
// "first": "Ben",
// "last": "Goldberg"
// },
// "age": 19
// },
// {
// "id": 2,
// "name": {
// "first": "Sandra",
// "last": "Jones"
// },
// "age": 21
// },
// {
// "id": 1,
// "name": {
// "first": "Jack",
// "last": "Smith"
// },
// "age": 37
// },
// {
// "id": 5,
// "name": {
// "first": "Lance",
// "last": "Heffernan"
// },
// "age": 43
// },
// {
// "id": 3,
// "name": {
// "first": "Julie",
// "last": "Cooper"
// },
// "age": 52
// }
// ]
Nice now we have our array in age order, youngest to oldest.
But putting age before beauty, we've changed our minds and decided we want our oldest people first instead.
You can switch the compare function around, and subtract a
from b
instead. This flips our number sorting to descending order and gives the highest numbers first.
people.sort((a, b) => b.age - a.age);
console.log(people);
// [
// {
// "id": 3,
// "name": {
// "first": "Julie",
// "last": "Cooper"
// },
// "age": 52
// },
// {
// "id": 5,
// "name": {
// "first": "Lance",
// "last": "Heffernan"
// },
// "age": 43
// },
// {
// "id": 1,
// "name": {
// "first": "Jack",
// "last": "Smith"
// },
// "age": 37
// },
// {
// "id": 2,
// "name": {
// "first": "Sandra",
// "last": "Jones"
// },
// "age": 21
// },
// {
// "id": 4,
// "name": {
// "first": "Ben",
// "last": "Goldberg"
// },
// "age": 19
// }
// ]
Now we have the oldest people at the front and the youngest at the back!
If you just want to reverse the sort, another option is to chain on the .reverse
array method after .sort
, e.g. myArray.sort().reverse()
.
What if you want to shuffle your array into a random order? You can use .sort
for that too, but there's another way to shuffle that's better for larger arrays. Check out the code in how to shuffle an array into a random order with JavaScript.