Finding the closest number downward to a different number from an array

左心房为你撑大大i 提交于 2019-12-06 05:11:25

问题


Example: I have an array like this: [0,22,56,74,89] and I want to find the closest number downward to a different number. Let's say that the number is 72, and in this case, the closest number down in the array is 56, so we return that. If the number is 100, then it's bigger than the biggest number in the array, so we return the biggest number. If the number is 22, then it's an exact match, just return that. The given number can never go under 0, and the array is always sorted.

I did see this question but it returns the closest number to whichever is closer either upward or downward. I must have the closest one downward returned, no matter what.

How do I start? What logic should I use?

Preferably without too much looping, since my code is run every second, and it's CPU intensive enough already.


回答1:


You can use a binary search for that value. Adapted from this answer:

function index(arr, compare) { // binary search, with custom compare function
    var l = 0,
        r = arr.length - 1;
    while (l <= r) {
        var m = l + ((r - l) >> 1);
        var comp = compare(arr[m]);
        if (comp < 0) // arr[m] comes before the element
            l = m + 1;
        else if (comp > 0) // arr[m] comes after the element
            r = m - 1;
        else // arr[m] equals the element
            return m;
    }
    return l-1; // return the index of the next left item
                // usually you would just return -1 in case nothing is found
}
var arr = [0,22,56,74,89];
var i=index(arr, function(x){return x-72;}); // compare against 72
console.log(arr[i]);

Btw: Here is a quick performance test (adapting the one from @Simon) which clearly shows the advantages of binary search.




回答2:


var theArray = [0,22,56,74,89];
var goal = 56;
var closest = null;

$.each(theArray, function(){
  if (this <= goal && (closest == null || (goal - this) < (goal - closest))) {
    closest = this;
  }
});
alert(closest);

jsFiddle http://jsfiddle.net/UCUJY/1/




回答3:


Array.prototype.getClosestDown = function(find) {            
    function getMedian(low, high) {
       return (low + ((high - low) >> 1));
    }

    var low = 0, high = this.length - 1, i;  

    while (low <= high) {
     i = getMedian(low,high);
     if (this[i] == find) { 
         return this[i]; 
     }        
     if (this[i] > find)  { 
         high = i - 1;
     }
     else  { 
         low = i + 1;
     }
  }  
  return this[Math.max(0, low-1)];
}

alert([0,22,56,74,89].getClosestDown(75));



回答4:


Here's a solution without jQuery for more effiency. Works if the array is always sorted, which can easily be covered anyway:

var test = 72,
    arr = [0,56,22,89,74].sort(); // just sort it generally if not sure about input, not really time consuming

function getClosestDown(test, arr) {
  var num = result = 0;

  for(var i = 0; i < arr.length; i++) {
    num = arr[i];
    if(num <= test) { result = num; }
  }

  return result;
}

Logic: Start from the smallest number and just set result as long as the current number is smaller than or equal the testing unit.

Note: Just made a little performance test out of curiosity :). Trimmed my code down to the essential part without declaring a function.




回答5:


As we know the array is sorted, I'd push everything that asserts as less than our given value into a temporary array then return a pop of that.

var getClosest = function (num, array) {
    var temp = [],
        count = 0,
        length = a.length;

    for (count; count < length; count += 1) {

        if (a[count] <= num) {
            temp.push(a[count]);
        } else {
            break;
        } 
    }

    return temp.pop();
}

getClosest(23, [0,22,56,74,89]);



回答6:


Here is edited from @Simon. it compare closest number before and after it.

var test = 24,
arr = [76,56,22,89,74].sort(); // just sort it generally if not sure about input, not really time consuming

function getClosest(test, arr) {
  var num = result = 0;
  var flag = 0;
  for(var i = 0; i < arr.length; i++) {
    num = arr[i];
    if(num < test) {
      result = num;
      flag = 1;
    }else if (num == test) {
      result = num;
      break;
    }else if (flag == 1) {
      if ((num - test) < (Math.abs(arr[i-1] - test))){
        result = num;
      }
      break;
    }else{
      break;
    }
  }
  return result;
}



回答7:


Here's an ES6 version using reduce, which OP references. Inspired by this answer get closest number out of array

lookup array is always sorted so this works.

const nearestBelow = (input, lookup) => lookup.reduce((prev, curr) => input >= curr ? curr : prev);
const counts = [0,22,56,74,89];
const goal = 72;
nearestBelow(goal, counts); // result is 56.

Not as fast as binary search (by a long way) but better than both loop and jQuery grep https://jsperf.com/test-a-closest-number-function/7



来源:https://stackoverflow.com/questions/15203994/finding-the-closest-number-downward-to-a-different-number-from-an-array

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!