【问题标题】:Finding the closest number downward to a different number from an array从数组中找到最接近的数字向下到不同的数字
【发布时间】:2013-03-04 14:36:25
【问题描述】:

示例:我有一个这样的数组:[0,22,56,74,89],我想找到最接近不同数字的数字。假设数字是72,在这种情况下,数组中最接近的数字是56,所以我们返回它。如果数字是100,那么它大于数组中最大的数字,所以我们返回最大的数字。如果数字是22,那么它是完全匹配的,只需返回即可。给定的数字永远不会小于 0,并且数组始终是有序的。

我确实看到了this question,但它返回最接近向上或向下的数字。无论如何,我必须让最近的一个向下返回。

我该如何开始?我应该使用什么逻辑?

最好不要太多循环,因为我的代码每秒运行一次,而且它已经足够占用 CPU。

【问题讨论】:

  • 而且数组总是排序的?
  • @Bergi 是的,编辑问题以反映这一点。

标签: javascript jquery arrays numbers


【解决方案1】:

您可以使用binary search 作为该值。改编自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]);

顺便说一句:这里有一个quick performance test(改编自@Simon 的那个),它清楚地展示了二分搜索的优势。

【讨论】:

  • 二分搜索是你能做的最好的。它会在 O(log n) 中返回您的值,尽管您没有意识到 .grep 本身就是一个循环,并且如果没有某种循环就无法完成这个问题,那么很容易理解为什么你没有意识到这一点。
  • 哇,更快?谢谢!在这种情况下,性能对我来说很重要,所以运行时间越短越好:)
  • @DJDavid98:当然,因为它是O(log n) :-) 但是您可能会注意到仅对大数组的影响,测试中的数组有 1000 个项目。
  • 不错的解决方案 :),但请注意,随着数组变大(在您的情况下,大小为 1000 个随机数),二进制搜索会更快,而对于像 10 或20. 见jsperf.com/test-a-closest-number-function/4。所以 OP 应该评估为他的案例采用哪个循环。
  • 顺便说一句:应该给 aquinas 一些功劳,因为他已经给出了二进制搜索解决方案,我认为扩展原型是一个不错的主意 ;)。
【解决方案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】:

      这是一个没有 jQuery 的解决方案,以提高效率。如果数组始终是排序的,则可以工作,无论如何都可以很容易地覆盖:

      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;
      }
      

      逻辑:从最小的数字开始,只要当前数字小于等于测试单元,就设置result

      注意:出于好奇,我只是做了一点performance test :)。在不声明函数的情况下将我的代码精简到基本部分。

      【讨论】:

        【解决方案5】:

        这是一个使用 reduce 的 ES6 版本,OP 引用了它。受此答案启发get closest number out of array

        查找数组总是排序的,所以这很有效。

        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.
        

        不如二分查找快(很长一段路),但比循环和 jQuery grep https://jsperf.com/test-a-closest-number-function/7 都好

        【讨论】:

          【解决方案6】:

          我们知道数组已经排序,我会将断言小于我们给定值的所有内容推送到一个临时数组中,然后返回其中的一个弹出窗口。

          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]);
          

          【讨论】:

          • 如果您只关心最后一个值,为什么不只拥有一个保存该值的变量呢?即,而不是 temp.push(a[count]); 只是这样做:currVal = a[count]; 然后 return currVal;
          【解决方案7】:

          这里是从@Simon 编辑的。 它比较前后最接近的数字。

          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;
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2013-09-12
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2019-07-19
            • 1970-01-01
            相关资源
            最近更新 更多