Create, register and use shortcodes in WordPress
18/03/2023Learn how to create and register your own WordPress shortcodes to add dynamic content to your posts and pages.
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()’!
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;
}
});
}
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!
Learn how to create and register your own WordPress shortcodes to add dynamic content to your posts and pages.
Learn how to improve code readability and performance by using guard clauses in JavaScript. Discover their benefits and best practices.
Learn the difference between implements and extends in TypeScript. Use Implements to implement interfaces and types, and extends to inherit from classes.
In this tutorial we will look at using YAML in PHP. Learn about Parsing and Writing YAML files using Symfony's YAML component.
Measuring code execution performance is an important way to identify bottlenecks. Use these methods in JavaScript to help optimise your code.
Find bottlenecks, optimise and clean your code, and speed up your apps by measuring the execution time of your PHP scripts using microtime.
Learn how to regenerate and update WordPress media and image sizes both programmatically (without plugin), and also with a handy plugin.
Ever seen constants like __DIR__ and __FILE__ being used in PHP? These are 'Magic Constants', and this is how we can use them.
Learn how to use event listeners to detect and handle single and multiple keypress events in JavaScript. Add modifier keys to your application!
Awesome post! Keep up the great work! 🙂
Great content! Super high-quality! Keep it up! 🙂
Can you please update on using array of Objects ?
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)
man you just saved my day…
I’ve been stuck at this for 2 days
this is awesome, you made me want to learn what I’ve been avoiding during a whole semester, thank you!
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);
This is exactly what I was looking for, props!
great
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?
Great post! I wondered how you would extend closest to match the closest object in an array to some fixed values e.g.
“`
const needleValues = {
a: 0,
b: 3,
c: 7,
d: 2
}
const items = [
{
// This first one should match
a: 0,
b: 3,
c: 7,
d: 2
},
{
a: 2,
b: 5,
c: 2,
d: 8
},
{
a: 1,
b: 7,
c: 2,
d: 9
}
]
“`
Thanks 🙂