custom sort functions with javascript

2018-12-14

 | 

~4 min read

 | 

613 words

Javascript’s built-in sort is powerful and fast. However, there are many times when you will want to sort in a custom fashion.

Whenever I wanted to create a custom sort, I kept referring back to MDN’s great page on the .sort() method.

This post is intended as a complement to that and one that pulls out some of the critical points I needed in order to grok how custom sorts worked in my most common use cases.

The Basics

Underpinning all of the sorting methods in Javascript are a few simple rules:

  1. The built-in sort function is a three-way comparison between two values a and b
  2. A return value > 0 means that the a is greater than b and will come after it
  3. A return value == 0 means the values are equal and it does not matter which comes first
  4. A return value of < 0 means that a is less than b and will come before it
const arr = [4, 1, 2, 5, 3, 2]

function ascendingSort(a, b) {
  if (a < b) {
    return -1
  }
  return 1
}

function descendingSort(a, b) {
  if (a < b) {
    return 1
  }
  return -1
}

console.log(`Native --> `, arr.sort()) // [ 1, 2, 2, 3, 4, 5 ]
console.log(`Ascending -> `, arr.sort(ascendingSort)) // [ 1, 2, 2, 3, 4, 5 ]
console.log(`Descending -> `, arr.sort(descendingSort)) // [ 5, 4, 3, 2, 2, 1 ]

Multi-Condition Sort

These same rules apply for a more complicated scenario. For example, let’s think about sorting an array where each element is itself an array.

The elements take the shape of [char, number], e.g., [a,2]

We want to sort in the following way:

  1. Sort the element’s first by the number in descending fashion (e.g., 9 before 8)
  2. If there’s a tie, sort the elements by the character in ascending order (e.g., a before b)
const nestedArray = [
  ["m", 1],
  ["i", 4],
  ["s", 4],
  ["p", 2],
]

function descNumbersAscChar(arrA, arrB) {
  if (arrA[1] > arrB[1]) {
    return -1
  } else if (arrA[1] === arrB[1]) {
    if (arrA[0] < arrB[0]) {
      return -1
    } else if (arrA[0] > arrB[0]) {
      return 1
    }
  } else if (arrA[1] < arrB[1]) {
    return 1
  } else {
    console.log("Uncaught situation!")
    return 1
  }
}

console.log(nestedArray.sort(descNumbersAscChar)) // [ [ 'i', 4 ], [ 's', 4 ], [ 'p', 2 ], [ 'm', 1 ] ]

Boolean Logic

One of the reasons that this took a while for things to click is that I was thinking in terms of boolean comparisons.

This is actually what Javascript is doing, but because it doesn’t want to look at the conditional (that is a < b), it relies on you to tell it what to do with a 1 and -1.

If you still want to use Boolean logic, however, it’s fairly straightforward.

Refactoring the ascendingSort function from earlier:

/**
* Boolean overview
* if (a < b) {
*   // do this because it's true
* } else {
*   // do this because it's false
* }
*/

const arr = [4,1,2,5,3,2];

function ascendingSortBool(a,b) {
  return +(a > b) || -(a < b)
}
console.log(`Ascending -> `, .sort(ascendingSortBool)) // [ 1, 2, 2, 3, 4, 5 ]

This works because function returns 1 if b and -1 if b < a. This avoids the issue of a false returning 0 which the .sort() wouldn’t do anything with.

Additional Resources



Hi there and thanks for reading! My name's Stephen. I live in Chicago with my wife, Kate, and dog, Finn. Want more? See about and get in touch!