在距离我最近的阵列中查找数字

时间:2013-07-08 08:21:36

标签: javascript underscore.js

我对javascript很新,我在找到解决问题的最有效方法时遇到了问题

我有一个对象数组。每个对象都有一个时间戳和一个总字段。我有一个数字保存为变量,我想循环遍历数组,找到对象的时间戳,总字段最接近我的数字。

这是一个排序数组,因此数字总是在增加,例如数字可能如下所示:

Jan 125 
Feb 150 
Mar 200 
Apr 275 

如果我的号码是205,我希望得到结果Mar

它们是取自mongoDb的对象,所以看起来像这样

{TimeStamp: "2013-06-24 01:00", Delivered: 464, Queued: 39, Total: 503}
{TimeStamp: "2013-07-02 01:00", Delivered: 485, Queued: 37, Total: 522}
{TimeStamp: "2013-07-05 01:00", Delivered: 501, Queued: 41, Total: 542}
{TimeStamp: "2013-07-08 09:48", Delivered: 501, Queued: 64, Total: 565}

4 个答案:

答案 0 :(得分:1)

如果列表已在右侧字段中排序,则可以使用此代码查找O(n)中的最小距离:

var data = [
    {total: 125, name: 'Jan'}, 
    {total: 150, name: 'Feb'}, 
    {total: 200, name: 'Mar'}, 
    {total: 275, name: 'Apr'}
];

function getClosest(arr, value) 
{
    var closest, mindiff = null;

    for (var i = 0; i < arr.length; ++i) {
        var diff = Math.abs(arr[i].total - value);

        if (mindiff === null || diff < mindiff) {
            // first value or trend decreasing
            closest = i;
            mindiff = diff;
        } else {
            // trend will increase from this point onwards
            return arr[closest];
        }
    }
    return null;
}

您可以跟踪当前最近的对象及其在搜索值和搜索值之间的相应(绝对)差异。

只要差异减小,您就会不断更新这两个值。当不再发生这种情况时,您可以立即返回,因为您知道它之后永远不会减少。

使用它:

getClosest(data, 200);

答案 1 :(得分:0)

var numbers = [122,231,323,53];
var myNumber = 200;
var difference = 9999; 
var nearest = null;
for (i = 0 ; i < numbers.lenght; i++){
    var candidate = numbers[i];
    var currentDifference = Math.abs(myNumber - candidate);
    if  (currentDifference  < difference) {
        nearest = candidate; difference = currentDifference;
    }
}

答案 2 :(得分:0)

我有这个有用的通用功能:

function min(ary, key) {
    return ary.map(function(x) {
        return [key ? key(x) : x, x]
    }).reduce(function(m, x) {
        return x[0] < m[0] ? x : m;
    })[1]
}

它使用key作为比较函数在数组中找到最小元素。适用于您的问题:

 number = ...
 closestTimestamp = min(arrayOfRecords, function(record) {
       return Math.abs(number - record.total)
 }).TimeStamp;

答案 3 :(得分:0)

您可以使用binary search作为该值。改编自this answer

function nearestIndex(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 // this[m] equals the element
            return m;
    }
    // now, l == r+1
    // usually you would just return -1 in case nothing is found
    if (l == arr.length) return r;
    if (r == 0) return 0;
    if (Math.abs(compare(arr[l])) > Math.abs(compare(arr[r]))) // "closer"
        return r;
    else
        return l;

}

var items = […];
var i=nearestIndex(items, function(x){return x.Total-532;}); // compare against 532
console.log(items[i].TimeStamp);