Contact!

Find the closest number in an array JavaScript

Find nearest number in array

Today I was making a ‘draggy’, ‘slidey’, web component, control, ‘thing’ which needed to snap to pre-determined positions when the drag ended. This meant that I had to find the closest number in an array to where my drag ended and animate a snap to that position.

This funny little problem seems to be a bit polarising because there are a few solutions you could roll with. In the end I decided to use reduce() mainly because it was my initial instinct, but also because it isn’t every day that you find an actual ‘use for reduce()’!

Find the closest value in array using reduce()

So how do you find the closest value in an array using reduce()?

First we need to know how to get the difference between 2 numbers in JavaScript. The easiest way to do this is to use Math.abs(), so lets use that.

Second we need a function to compare each value of an array and return the closest to our ‘needle’. This is where reduce() comes in. Reduce will run a callback function on each element in an array and then return the result of the last callback invocation. Lets have a look:

const needle = 8;

const closest = [1, 10, 7, 2, 4].reduce((a, b) => {
    return Math.abs(b - needle) < Math.abs(a - needle) ? b : a;
});

console.log(closest); // Output: 7

With this function we check whether the absolute value of (b – 8) is less than the absolute value of (a – 8) and then return the winner. ‘a’ becomes the winner and is then checked against the next value in the array. We do this until every value has been evaluated, returning 7 in the last invocation.

The main issue with this approach is that it will return the first ‘nearest’ number it comes across. If we were to push 9 to the end of the array then 7 would still be returned because it is the first ‘nearest’ value to be evaluated.

Obviously this can matter, and if it does to you then it should be checked for in our reduce function.

const needle = 8;

const closest = [1, 10, 7, 2, 4, 9].reduce((a, b) => {
    let aDiff = Math.abs(a - needle);
    let bDiff = Math.abs(b - needle);

    if (aDiff == bDiff) {
        // Choose largest vs smallest (> vs <)
        return a > b ? a : b;
    } else {
        return bDiff < aDiff ? b : a;
    }
});

console.log(closest);

In this example we are returning the largest number. To make this return the smallest number we simply change ‘a > b ? a : b’ to ‘a < b ? a : b’.

If we want to turn this into a reusable function then we could do something like this:

function closest(needle, haystack) {
    return haystack.reduce((a, b) => {
        let aDiff = Math.abs(a - needle);
        let bDiff = Math.abs(b - needle);

        if (aDiff == bDiff) {
            return a > b ? a : b;
        } else {
            return bDiff < aDiff ? b : a;
        }
    });
}

Find the closest value in array using sort()

Another approach is to sort() the array by closest absolute value to our ‘needle’. This would mean that position [0] of our array is now the closest match.

const needle = 8;
const numbers = [1, 10, 7, 2, 4, 9];

numbers.sort((a, b) => {
    return Math.abs(needle - a) - Math.abs(needle - b);
})

console.log(numbers[0]);

I don’t like this approach as much because the previous solution feels ‘neater’ as the reducer returns a single value… reduce() actually executes faster, too!

Join the discussion!

You might like: