Explain Codes LogoExplain Codes Logo

Get the closest number out of an array

javascript
functions
currying
promises
Nikita BarsukovbyNikita Barsukov·Sep 14, 2024
TLDR

Let's find the closest number to a target in an array using good old Array.prototype.reduce():

const nearest = (arr, target) => arr.reduce((a, b) => Math.abs(b - target) < Math.abs(a - target) ? b : a); // Usage case: let closeEncounter = nearest([5, 20, 12, 16, 25], 15); console.log(closeEncounter); // Output: 16

The architect of success here is comparing the Math.abs differences to the target - the smallest divergence gives us our closest number.

Checkmate edge cases: "Hold my coffee"

Before being an array ninja, let's ready our defenses against potential Gotchas.

Edge control: on point

Before embarking on the closest number quest, we ensure our arsenal (arr and target) are in form:

  • The arr is not hanging out in the void (a.k.a empty).
  • arr soldiers and our target are true numbers, not just masquerading.
  • Our target doesn't go rogue, staying within bounds (-1000 to 1000).

Our code might look like this:

const nearest = (arr, target) => { if (!arr.length) throw new Error("Array's gone ghost. 👻"); // Array can't be empty if (!arr.every(Number.isFinite)) throw new Error("Array soldiers aren't all numbers. 🕵️"); // Target check: Don't go rogue! if (isNaN(target) || Math.abs(target) > 1000) throw new Error("Target's out of bounds. 🎯⛔"); // Now, where's my coffee? ☕ return arr.reduce((a, b) => Math.abs(b - target) < Math.abs(a - target) ? b : a); };

Sorted arrays: Order in a chaotic world

In case of a massive arr, a binary search zips through our data with O(log N) performance boost. Yes, you heard it -maths guys call it "logarithmic time".

  1. First, we align the array elements. Chaos has no place here.
  2. We implement an efficient binary search to station the closest index.
const binSearchNearest = (arr, target) => { let start = 0, end = arr.length - 1; while (start <= end) { let mid = Math.floor((start + end) / 2); if (arr[mid] === target) return arr[mid]; // Jackpot! 🎰 arr[mid] < target ? start = mid + 1 : end = mid - 1; } const closest = ((arr[start] - target) < (target - arr[end])) ? arr[start] : arr[end]; // Champions stand-off return closest; };

Currying: Flavour of functional programming

Nothing like a dash of currying to spruce up our function, allowing its reuse for different scenarios.

const curryNearest = target => arr => arr.reduce((a, b) => Math.abs(b - target) < Math.abs(a - target) ? b : a); // Serving: Curry with target = 15 let nearestTo15 = curryNearest(15); console.log(nearestTo15([5, 20, 12, 16, 25])); // Output: 16

Special scenarios: Above and beyond

Now that we conquered the basics, let's scoot over to complex terrains.

Array includes the target: What a hit!

In rare occurrences, our arr might be holding the target captive. We simply return it:

if(arr.includes(target)) return target; // Jackpot! 🎰

This also doubles as our early exit stratagem, improving performance where an exact match is spotted.

Currying adjustment: Change is the only constant

Finally, curryNearest helps us shuffle the target values for distinct scenarios; through placeholders:

// Serving: Curry with target = 10 const nearestTo10 = curryNearest(10);

Libraries for currying: A pinch of lodash

Show off your prowess by leveraging libraries like Lodash to ship out curry function:

const _ = require('lodash'); const curryNearest = _.curry((target, arr) => arr.reduce(/*... */));