使用JavaScript查找数组中的最接近日期

问题描述 投票:7回答:5

我有一个数组,里面有几天。每天都是一个对象,例如:

{day_year: "2012", day_month: "08", day_number: "03", day_name: "mon"}

我还使用以下方法将时间戳记属性添加到了每天的对象中:

function convertDays() {
    var max_i = days.length;
    for(var i = 0; i < max_i; i++) {
        var tar_i = days[i];
        tar_i.timestamp = new Date(tar_i.day_year, tar_i.day_month, tar_i.day_number);
    }
}

数组中的日期是任意的,因此没有真正的逻辑。

现在,我想找到距给定日期最近的两天。因此,如果带天的数组包含

  • 2012年8月2日
  • 2012年8月4日
  • [2012年8月23日

并且我搜索2012年8月11日,希望它返回2012年8月4日和2012年8月23日。

我尝试使用另一个问题的答案,看起来像这样:

function findClosest(a, x) {
    var lo, hi;
    for(var i = a.length; i--;) {
        if(a[i] <= x && (lo === undefined || lo < a[i])) lo = a[i];
        if(a[i] >= x && (hi === undefined || hi > a[i])) hi = a[i];
    }
    return [lo, hi];
}

但是,它返回unidentified

什么是最有效的方法(最少的处理器/内存密集型方法)?

编辑:“但是,结果如何“奇怪”?您能否提供代码和数据的示例?”

我现在正在使用以下内容来生成日期数组:

var full_day_array = [];
for(var i = 0; i < 10; i++) {
    var d = new Date();
    d.setDate(d.getDate() + i);
    full_day_array.push({day_year: d.getFullYear().toString(), day_month: (d.getMonth() + 1).toString(), day_number: d.getDate().toString()});
}

奇怪的是,使用下面的代码,这仅适用于10个或更短日期的数组。每当我使用11个或更多日期的数组时,结果就会变得出乎意料。

例如:使用15个日期组成的数组,从2012年8月6日到2012年8月21日。如果我再调用findClosest(full_day_array, new Date("30/07/2012");,则希望它返回{nextIndex: 0, prevIndex: -1}。但是,它返回{nextIndex: 7, prevIndex: -1}。为什么?

function findClosest(objects, testDate) {
    var nextDateIndexesByDiff = [],
        prevDateIndexesByDiff = [];

    for(var i = 0; i < objects.length; i++) {
        var thisDateStr = [objects[i].day_month, objects[i].day_number, objects[i].day_year].join('/'),
            thisDate    = new Date(thisDateStr),
            curDiff     = testDate - thisDate;

        curDiff < 0
            ? nextDateIndexesByDiff.push([i, curDiff])
            : prevDateIndexesByDiff.push([i, curDiff]);
    }

    nextDateIndexesByDiff.sort(function(a, b) { return a[1] < b[1]; });
    prevDateIndexesByDiff.sort(function(a, b) { return a[1] > b[1]; });


    var nextIndex;
    var prevIndex;

    if(nextDateIndexesByDiff.length < 1) {
        nextIndex = -1;
    } else {
        nextIndex = nextDateIndexesByDiff[0][0];
    }
    if(prevDateIndexesByDiff.length < 1) {
        prevIndex = -1;
    } else {    
        prevIndex = prevDateIndexesByDiff[0][0];
    }
    return {nextIndex: nextIndex, prevIndex: prevIndex};
}
javascript arrays search
5个回答
20
投票

您可以通过自定义比较器功能轻松使用sort function


9
投票

如果使用 var distancea = Math.abs(diffdate - a.the_date_object); var distanceb = Math.abs(diffdate - b.the_date_object); 对象的数组而不是您自己定义的结构,则可以在O(N)中轻松实现:


6
投票

var testDate = new Date(...); var bestPrevDate = days.length; var bestNextDate = days.length; var max_date_value = Math.abs((new Date(0,0,0)).valueOf()); var bestPrevDiff = max_date_value; var bestNextDiff = -max_date_value; var currDiff = 0; var i; for(i = 0; i < days.length; ++i){ currDiff = testDate - days[i].the_date_object; if(currDiff < 0 && currDiff > bestNextDiff){ // If currDiff is negative, then testDate is more in the past than days[i]. // This means, that from testDate's point of view, days[i] is in the future // and thus by a candidate for the next date. bestNextDate = i; bestNextDiff = currDiff; } if(currDiff > 0 && currDiff < bestPrevDiff){ // If currDiff is positive, then testDate is more in the future than days[i]. // This means, that from testDate's point of view, days[i] is in the past // and thus by a candidate for the previous date. bestPrevDate = i; bestPrevDiff = currDiff; } } /* days[bestPrevDate] is the best previous date, days[bestNextDate] is the best next date */ 答案非常好,但是如果您想知道任一方向上最近的N个对象,我对如何处理这个问题很感兴趣。这是我的刺:


0
投票

不管日期数组有多长,这都有效:


0
投票
function newFindClosest(dates, testDate) {
    var before = [];
    var after = [];
    var max = dates.length;
    for(var i = 0; i < max; i++) {
        var tar = dates[i];
        var arrDate = new Date(tar.day_year, tar.day_month, tar.day_number);
        // 3600 * 24 * 1000 = calculating milliseconds to days, for clarity.
        var diff = (arrDate - testDate) / (3600 * 24 * 1000);
        if(diff > 0) {
            before.push({diff: diff, index: i});
        } else {
            after.push({diff: diff, index: i});
        }
    }
    before.sort(function(a, b) {
        if(a.diff < b.diff) {
            return -1;
        }
        if(a.diff > b.diff) {
            return 1;
        }
        return 0;
    });

    after.sort(function(a, b) {
        if(a.diff > b.diff) {
            return -1;
        }
        if(a.diff < b.diff) {
            return 1;
        }
        return 0;
    });
    return {datesBefore: before, datesAfter: after};
}
© www.soinside.com 2019 - 2024. All rights reserved.