Programming

Sorting An Array of Objects

This post has been on my mind for a while. Today, I would like to talk about sorting an array of objects. This exercise assumes your array is uniform, meaning all elements in the array are of the same type. To keep things more simple, I’ll assume you know what you are doing and we won’t check whether the array is uniform.

Additionally, we’ll keep this functionality as part of Array prototype so you can keep using it as if it is a native method rather than passing your array as an argument. One last note before we dive into the code is that while we are implementing our solution, we may as well throw in a way to sort the array ascendingly or descendingly.

The Key Element

Let’s look at the following array of objects.

var arr = [
  { name: "Kubar", age: 38, signedUpAt: new Date("April 3, 2008") },
  { name: "Rudy", age: 2, signedUpAt: new Date("May 25, 2018") },
  { name: "Okan", age: 37, signedUpAt: new Date("June 12, 1998") }
];

The property values in each object are fairly random. You have name property almost sorted out. Age is a numerical value, whereas signedUpAt is a date type. I mentioned the solution being in the prototype of Array so let’s start there.

Array.prototype.sortBy = function(key, ascending = true) {};

The first argument, key, is the key we are going to use to know about the value we want to sort. Imagine you want to sort your array of objects by name or age. The key in your objects is the first argument you pass to sortBy so it can do a lookup. The secondary argument, ascending, is actually a bonus here. Since you are going to write a custom sort algorithm, why not choose the direction of the sort? There is actually a much more practical reason for it too. Normally, when you use the default sort, which sorts the values in ascending order, you can easily use the native reverse method for arrays to get values in descending order. Well, you can’t do that in an array of objects, can you? That is why we are writing this code in the first place. Objects are not sortable naturally.

Array.prototype.sortBy = function(key, ascending = true) {
  return this.sort((a, b) => {
    if (ascending) {
      return a[key] > b[key] ? 1 : a[key] < b[key] ? -1 : 0;
    } else {
      return a[key] > b[key] ? -1 : a[key] < b[key] ? 1 : 0;
    }
  });
};

As you can see, we are actually piggybacking on the original sort by not comparing the whole object to the next but rather comparing the object’s value for a particular key. Ignore the if block with ascending for a moment and just focus on the following line of code.

return a[key] > b[key] ? 1 : a[key] < b[key] ? -1 : 0;

This code is very similar to the regular sort. You can find a longer explanation of it here, in the description section. As I mentioned earlier, you lose the functionality to reverse the values of a typical sort with an array of objects. That’s why we need to introduce a conditional block to reverse the sort order in our function. There is, of course, a shorter way of writing it by merging the if-else block into the existing ternary statements but then it would like this, pretty unreadable.

Array.prototype.sortBy = function(key, ascending = true) {
  return this.sort(
    (a, b) =>
      a[key] > b[key]
        ? ascending
          ? 1
          : -1
        : a[key] < b[key]
          ? ascending
            ? -1
            : 1
          : 0
  );
};

Conclusion

Whether you choose the more legible piece of code or not, sorting an array of objects is actually trivial. You can now use by calling it on an ordinary array.

arr.sortBy("age",false);
arr.sortBy("name");
arr.sortBy("signedUpAt",false);

However, if the objects in your array are more complex and they contain objects nested inside, you can’t use this method. You’d have to further break it down either manually or maybe rely on a recursive implementation. My goal in this post was to show the basic functionality, now it’s up to you to change it according to your project’s needs.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.