A
A
Alexey Strukov2017-06-17 22:13:13
JavaScript
Alexey Strukov, 2017-06-17 22:13:13

What is the best way to solve the problem of finding the nearest number?

Greetings. Here is the essence of the task:
There is a function findClosest , which takes an unsorted array of numbers, the number to be found and a comparator function. The comparator must define one of 4 possible behaviors for findClosest :
If the number is not in the array, then:

  • find the nearest smaller number
  • find the nearest larger number
  • find the nearest number, but if it is equidistant from the array values, take what is less
  • find the nearest number, but if it is equidistant from the array values, take whichever is greater

If there is no data in the array that matches the condition, return false :
What are some elegant solutions?

Answer the question

In order to leave comments, you need to log in

3 answer(s)
A
Alexey Strukov, 2017-06-28
@pm_wanderer

Here is the solution I found (if anyone needs it in the future):

/**
     * @param {Array} settings.arr
     * @param {Number} settings.valueToFind
     * @param {Function} settings.comparator
     *
     * @returns {Number|undefined}
     */
    function findClosest(settings) {

      var lo                 = -Infinity,
            hi                 = Infinity,
            arr                = settings.arr,
            valueToFind = settings.valueToFind,
            comparator  = settings.comparator,
            result;

        for (var i = 0; i < arr.length; i++) {

            if (arr[i] <= valueToFind && arr[i] >= lo) {
                lo = arr[i];
                continue;
            }

            if (arr[i] >= valueToFind && arr[i] <= hi) {
                hi = arr[i];
            }
        }

        result = comparator(lo, hi, valueToFind);

        return isFinite(result) ? result : undefined; // or false
    }

This is what the settings object looks like with four possible comparators:
var comparator1 = function(lo, hi, valueToFind) {
        return lo; // or hi
};

var comparator2 = function(lo, hi, valueToFind) {
        var result = lo; // or hi

        switch (true) {
            case valueToFind - lo < hi - valueToFind:
                result = lo;
                break;
            case valueToFind - lo > hi - valueToFind:
                result = hi;
                break;
        }

        return result;
};
 
var settings = {
        arr: [1, 5, 10, 8, 5, 13],
        valueToFind: 7,
        comparator: comparator2
};

And the function call itself:
PS:
Instead of false, in the case when the result is not defined, I decided to return undefined, since this value is closer in semantics.

N
Nurba Nurba, 2017-06-17
@nurba91

sort the array with some sort of algorithm. after finding numbers by binary search)

T
tomatho, 2017-06-18
@tomatho

For the third and fourth options, it is impossible to find out from the comparator whether it was already at the same distance.
The way out that I see is to "shift" in favor of the "bottom", but this is possible only with a certain accuracy.
The second option: you can do it if you pass three values ​​​​to the comparator: current, best now, and what we are looking for.
Further code for a, b - current , what we are looking for , respectively.
Didn't check the code.

function c1(a, b) {
  return (a <= b ? b - a : Number.MAX_VALUE );
}
function c2(a, b) {
  return (a >= b ? a - b : Number.MAX_VALUE );
}
function c3(a, b) {
  if (a <= b && b - a < Math.abs(b)*(1e-7))
    return 0;
  return Math.abs(a - b + Math.abs(b)*(1e-7));
}
function c4(a, b) {
  if (a >= b && a - b < Math.abs(b)*(1e-7))
    return 0;
  return Math.abs(a - b - Math.abs(b)*(1e-7));
}

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question