如何使用lodash从数组中获取前两个最接近目标的数字?

时间:2014-11-15 11:37:42

标签: javascript lodash

我是lodash的新手,只是通过javascript获得函数式编程的感觉。我正在使用lodash 3.0.0-pre。

我有一系列有序的数字和目标数字。

我需要一个带有第一个和第二个最接近数字的数组,除非它是最后一个数字然后我只需要它。我怎么用lodash得到它?

我找到了:

function getClosest(array, target) {
    var tuples = _.map(array, function(val) {
        return [val, Math.abs(val - target)];
    });
    return _.reduce(tuples, function(memo, val) {
        return (memo[1] < val[1]) ? memo : val;
    }, [-1, 999])[0];
}

我可以改变它给我最接近的两个而不是一个,但我相信它会在整个阵列中排序,而不是只有在它有所需的两个数字时才停止,因为它可以在数字差异开始增加时停止

4 个答案:

答案 0 :(得分:0)

不是真正的lodash任务,因为它不是一个简单的n - &gt; n或n - > 1转型。此外,lodash不允许您提前取消声明。

无论如何,这是一个解决方案:

var array= [2, 3, 5, 25, 135, 250, 300];

function getClosest(array, target) {
    var tuples = _.map(array, function(val) {
        return [val, Math.abs(val - target)];
    });

    var prev= [0, Number.MAX_VALUE];
    for(var i=0; i<tuples.length; i++){
        if(tuples[i][1] < prev[1]){
            prev= tuples[i];
        }else{
            if(i<2 || tuples[i][1] < tuples[i-2][1]){
                return [prev[0], tuples[i][0]];
            }else{
                return [prev[0], tuples[i-2][0]];
            }
        }
    }
    return [prev[0]];
}

console.log(getClosest(array, 3));

可以通过使用牛顿方法找到最近的元素然后查看之前和之后的元素来进行优化。 (如果你的数组中有50000个数字^^)

答案 1 :(得分:0)

假设您的数组已排序并且arr[0] ≤ target

var getClosests =  function (arr, target) {
  var last = _.last(arr)
  if (target > last) {
    return [last];
  }
  var index = _.findIndex(arr, function(a) { return target - a <= 0 });
  neighbours = [arr[index-1], arr[index], arr[index+1]]
  return _.chain(neighbours).sortBy(function(a) { 
    return Math.abs( a - target) })
  .take(2).value()
}

getClosests([2, 3, 5, 25, 135, 250, 300], 100);
getClosests([2, 3, 5, 25, 135, 250, 300], 25);
getClosests([2, 3, 5, 25, 135, 250, 300], 400);

答案 2 :(得分:0)

如果你关心性能,我建议你不要在这里使用lodash循环函数。 一旦你订购了数组 - 最好使用Binary search的修改版本来查找最接近的值的索引:

function closestIndex(arr, target) {
    var i = 0, j = arr.length - 1, k;   

    while (i <= j) {
       k = Math.floor((i+j) / 2);
       if (target === arr[k] || Math.abs(i - j) <= 1 ) {
           return k;
       } else if (target < arr[k]) {
           j = k-1;
       } else {
           i = k+1;
       }
    }
    return -1;
}

然后简单地比较数组中的相邻元素:

if (_.isNumber(arr[closestIndex - 1]) && _.isNumber(arr[closestIndex + 1])) {
    if (Math.abs(target - arr[closestIndex - 1]) < Math.abs(target - arr[closestIndex + 1])) {
        result.push(arr[closestIndex - 1]);
    } else {
        result.push(arr[closestIndex + 1]);
    }
}

请参阅完整示例here

答案 3 :(得分:0)

在阵列中找到两个壁橱到给定的目标:(无Lodash)

function findCloset(givenList, goal) {
  var first;
  var second;
  var finalCollection = [givenList[0], givenList[1]];
  givenList.forEach((item, firtIndex) => {
    first = item;

    for (let i = firtIndex + 1; i < givenList.length; i++) {
      second = givenList[i];

      if (first + second < goal) {
        if (first + second > finalCollection[0] + finalCollection[1]) {
          finalCollection = [first, second];
        }
      }
    }
  });

  return finalCollection;
}

var counts = [2, 42, 82, 329, 122, 40, 162, 202, 3, 5, 242, 282, 322, 35, 362];
var goal = 80;
console.log(findCloset(counts, goal));