在数组中查找最接近给定数字的数字

时间:2011-01-26 23:53:38

标签: javascript arrays algorithm math

我在javascript中有一个整数数组,[5,10,15,20,25,30,35] 给定数字x时,如何在数组中找到最接近该数字的元素?

如果数字超过一个值,但不到下一个数字的一​​半,我会选择较小的值,如果它超过下一个数字的一​​半,我会选择更高的数字。

例如7会返回5,但8会返回10.我怎样才能完成此操作?任何帮助或提示将不胜感激。我搜索过,找不到解决方案。我确信这很常见。

7 个答案:

答案 0 :(得分:25)

最简单的做法可能是根据距参考值x的距离进行排序,然后选择第一项。

内置Array.prototype.sort()可以使用比较函数,该函数将从数组中调用值对。然后关键是传递一个比较函数,该函数根据它们与参考值x的距离来比较这两个值。

let x = 8;
let array = [5, 10, 15, 20, 25, 30, 35];
let closest = array.sort( (a, b) => Math.abs(x - a) - Math.abs(x - b) )[0];

请参阅此简单demo

答案 1 :(得分:16)

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

如果使用函数方法适用,那么您可以将集合映射到(值,距离)的元组,然后将该组元组减少到具有最小距离的元组。我们返回该元组中的值。

解释_.map的用法。您将数组中的所有值映射到新值,该函数将返回新值的数组。在这种情况下是一个元组数组。

解释_.reduce的用法。您将数组减少为单个值。你传入一个数组和一个备忘录。当您在阵列中移动时,备忘录是您的“运行计数器”。在这种情况下,我们检查当前元组是否比备忘录更接近,如果是,则将其作为备忘录。然后我们在最后返回备忘录。

上面的代码片段依赖于underscore.js来删除功能样式javascript的细节

答案 2 :(得分:11)

您的示例列表已排序。如果总是如此,则二进制搜索您的号码。如果找不到确切的数字,请通过检查数字 所在的两个数字来结束二进制搜索,并返回最接近的数字。小心所有数字都大于或者都小于目标数

的边缘情况

如果列表并不总是排序,则通过列表跟踪最大数字&lt; =目标数量和最小数量&gt; =目标数量。返回最接近目标的那个。

在任何一个解决方案中,如果你在[1,3]中搜索2,你需要决定支持哪一方。

答案 3 :(得分:5)

创建一个与原始数组大小相同的临时数组,并用x和数组元素之间的差异填充它。

例如,让临时数组为temp [],原始数组为[]:

temp[i]=Math.abs(x-a[i]);

然后,将temp []中最小值的索引返回给用户。

答案 4 :(得分:0)

假设数组已排序,请逐步遍历数组中的每个相邻整数对。对于每对(例如“5和10”或“20和25”),测试 x 是否位于它们之间,如果是,则返回更接近 x (偏向较低者)。

x 小于第一个数字(返回第一个数字)或大于最后一个数字(返回最后一个数字)时,您还需要一个特殊情况。

如果数组未排序,请先排序。

答案 5 :(得分:0)

我创建了自己的功能,因为我找不到符合我要求的任何功能。

    function closest_number(quantities, number, closest_factor)
    {
        if (closest_factor == 'ceil')
        {
            quantities.sort(function(a, b)
                {
                    return a - b
                }
            );

            for (var i = 0; i < quantities.length; i++)
            {
                if (quantities[i] >= number)
                {
                    return quantities[i];
                }

                last_value = quantities[i];
            }

            return last_value;
        }
        else if (closest_factor == 'floor')
        {
            quantities.sort(function(a, b)
                {
                    return a - b
                }
            );

            min_value = quantities[0];

            for (var i = 0; i < quantities.length; i++)
            {
                if (number == quantities[i])
                {
                    return number;
                }
                else if (quantities[i] < number)
                {
                    min_value = quantities[i];
                }
                else if(quantities[i] > number)
                {
                    return min_value;
                }           
            }

            return min_value;
        }
        else
        {
            return false;
        }
    };

答案 6 :(得分:0)

由于Array.reduce长期存在(even IE9 supports it),因此可以轻松解决此问题。这样,无需先对数组排序(根本不需要数组突变):

var numbers = [20, 25, 30, 35, 5, 10, 15], x = 7;

var output = numbers.reduce(function (prev, curr) {
  return Math.abs(curr - x) < Math.abs(prev - x) ? curr : prev
});

console.log(output);

您可以使用箭头功能(但在本例中为no IE support),仅用一行ES6(ECMAScript 2015)语法来解决该问题: >

const numbers = [20, 25, 30, 35, 5, 10, 15], x = 7;

const output = numbers.reduce((prev, curr) => Math.abs(curr - x) < Math.abs(prev - x) ? curr : prev);

console.log(output);

当然,出于灵活性和可重用性,将其作为函数很容易:

const closest = (array, goal) => array.reduce((prev, curr) => Math.abs(curr - goal) < Math.abs(prev - goal) ? curr : prev);

console.log(closest([20, 25, 30, 35, 5, 10, 15], 7));
console.log(closest([20, 25, 30, 35, 5, 10, 15], 8));
console.log(closest([1, 5, 7], -5));
console.log(closest([1, 5, 7], 4));
console.log(closest([1, 5, 7], 20));