I have a method getClosest()
in an object, that does the following:
Given a number: Find the closest number in a list of unique and sorted numeric values.
On top of that it has two additional ptions next|offset
:
- default: find the closest value, smaller or larger than the submitted value
- next: find the next value in the list, that is larger than the submitted one
- offset: like default but find the smaller value only, if the distance to it is smaller/equal than a given delta
You can also assume that:
- the input value will always be smaller then or equal to the largest value in the set
- all parameters have the correct type (
integer|boolean
) - the list will contain between 10-20 values
This is an example of the list:
this.values = [0, 35, 90, 110, 160, 175, 200];
The function returns an object, holding the position as well as the actual value:
{
index: 1,
value: 35
}
class Test {
constructor() {
this.values = [0, 35, 90, 110, 160, 175, 200];
this.delta = 12;
}
getClosest(offset, next, value) {
let closest,
comparativeValue;
if (offset === true) {
for (let i = 0; i < this.values.length; ++i) {
const current = this.values[i];
if (value <= current) {
closest = {
index: i,
value: current
};
break;
}
if (value > current) {
comparativeValue = {
index: i,
value: current
};
}
}
if (comparativeValue) {
const offsetA = Math.abs(closest.value - value);
const offsetB = Math.abs(comparativeValue.value - value);
if (this.delta < offsetA && this.delta > offsetB) {
return comparativeValue;
}
}
}
if (next === true) {
for (let i = 0; i < this.values.length; ++i) {
const current = this.values[i];
if (current > value) {
closest = {
index: i,
value: current
};
break;
}
}
}
if (!offset && !next) {
for (let i = 0, shortest = null; i < this.values.length; ++i) {
const current = this.values[i];
const delta = Math.abs(current - value);
if (null === shortest || shortest > delta) {
closest = {
index: i,
value: current
};
shortest = delta;
}
}
}
return closest;
}
}
const test = new Test();
console.log(
test.getClosest(false, false, 10).value,
test.getClosest(false, false, 100).value,
test.getClosest(false, true, 10).value,
test.getClosest(false, true, 100).value,
test.getClosest(true, false, 10).value,
test.getClosest(true, false, 100).value,
);
My concerns are:
- overcomplicated
- this ain't DRY at all
- too many loops and variable declarations
- there's a call
getClosest(true, true, 40)
, which might lead to unexpected results
You can ignore the Test
-object-wrapper. It's to simplify the example and to make the code easily runnable. Here's a fiddle as well to play around with.
getClosest(true, false, 99).value
be90
instead of110
? The distance to90
is9
which is "smaller/equal than [the] given delta". \$\endgroup\$default
,next
, andoffset
should work together. \$\endgroup\$