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!

  1. SEO Company says:

    Awesome post! Keep up the great work! 🙂

  2. AffiliateLabz says:

    Great content! Super high-quality! Keep it up! 🙂

  3. Nischith says:

    Can you please update on using array of Objects ?

    1. Brian says:

      Hi Nischith,

      I believe in reduce(a, b)… the ‘a’ and ‘b’ ref the element or object in an array.

      So if you had an array of objects instead of numbers ‘a’ and ‘b’ would ref the object in the array.

      To ref a property in the object within your array you would use a.property and b.property in your code replacing ‘property’ with your actual key in your object.

      You could do this also if it makes more sense…

      arr.reduce(obj1, obj2 => {
      obj1.yourObjectKey obj2.yourObjectKey
      })

      (obj1, obj2) are the same as (a, b)

  4. pedi says:

    man you just saved my day…
    I’ve been stuck at this for 2 days

  5. Montserrat says:

    this is awesome, you made me want to learn what I’ve been avoiding during a whole semester, thank you!

  6. Brian says:

    Great post! This really saved me lots of mental energy and time!! I ended up using the .sort() because I needed the 10 closets values to a number.

    const allComps = soldsWithForSales
    .filter(prop => prop.result === true)
    .sort((a, b) => {
    // sorts all comps is order closest subject valuation
    return Math.abs(subVal – a.price) – Math.abs(subVal – b.price);
    });

    const topTen = allComps.slice(0, 10);

  7. matteo says:

    This is exactly what I was looking for, props!

  8. jaymangal says:

    great

  9. David Momoh says:

    Thank you for the great content sir. I want to ask, What if the needle parameter is also an array. How then do you do it?

Join the discussion!

You might like: