15

私はそれに日を含む配列を持っています。毎日がオブジェクトです。たとえば、次のようになります。

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

配列内の日は任意であるため、実際のロジックはありません。

ここで、特定の日付に最も近い 2 日を見つけたいと考えています。したがって、日の配列に含まれる場合

  • 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 個以上の日付の配列を使用すると、予期しない結果になります。

例: 2012 年 8 月 6 日から 2012 年 8 月 21 日までの 15 の日付の配列を使用し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};
}
4

6 に答える 6

26

sortこの関数は、カスタムコンパレータ関数で簡単に使用できます。

// assuming you have an array of Date objects - everything else is crap:
var arr = [new Date(2012, 7, 1), new Date(2012, 7, 4), new Date(2012, 7, 5), new Date(2013, 2, 20)];
var diffdate = new Date(2012, 7, 11);

arr.sort(function(a, b) {
    var distancea = Math.abs(diffdate - a);
    var distanceb = Math.abs(diffdate - b);
    return distancea - distanceb; // sort a before b when the distance is smaller
});

// result:
[2012-08-05, 2012-08-04, 2012-08-01, 2013-03-20]

の前後の結果のみを取得するには、そのために配列をフィルタリングdiffdateできます。

var beforedates = arr.filter(function(d) {
    return d - diffdate < 0;
}),
    afterdates = arr.filter(function(d) {
    return d - diffdate > 0;
});

オブジェクトを含むカスタム配列がある{the_date_object: new Date(...)}場合は、ソートアルゴリズムを次のように適応させる必要があります。

    var distancea = Math.abs(diffdate - a.the_date_object);
    var distanceb = Math.abs(diffdate - b.the_date_object);
于 2012-08-03T13:08:16.803 に答える
12

Date独自に定義した構造の代わりにオブジェクトの配列を使用すると 、O(N) で非常に簡単に実現できます。

var testDate = new Date(...);
var bestDate = days.length;
var bestDiff = -(new Date(0,0,0)).valueOf();
var currDiff = 0;
var i;

for(i = 0; i < days.length; ++i){
   currDiff = Math.abs(days[i] - testDate);
   if(currDiff < bestDiff){
       bestDate = i;
       bestDiff = currDiff;
   }   
}

/* the best date will be days[bestDate] */

配列がソートされている場合、二分探索で O(log N) で達成できます。

編集:「日付の前後の両方最も近い一致を見つけることが重要です」

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 */
于 2012-08-03T12:09:14.193 に答える
7

ゼータの答えは素晴らしいですが、どちらの方向にも最も近い N 個のオブジェクトを知りたい場合に、これにどのようにアプローチするかに興味がありました。ここに私の刺し傷があります:

var objects = [
    { day_year: "2012",
      day_month: "08",
      day_number: "02"
    },
    { day_year: "2012",
      day_month: "08",
      day_number: "04"
    },
    { day_year: "2012",
      day_month: "08",
      day_number: "23"
    }
];

var testDate = new Date('08/11/2012'),
    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]; });

console.log(['closest future date', objects[nextDateIndexesByDiff[0][0]]]);
console.log(['closest past date', objects[prevDateIndexesByDiff[0][0]]]);
于 2012-08-03T13:10:20.243 に答える
1

使用するものは次のとおりです。

この関数は、配列内で dateToCompareに最も近い日付 ( dateParamという名前) を持つ項目を探します。

項目[ dateParam ] について、dateToCompare に最も近い日付を持つ配列の要素を返します

getClosestDateInArray (array, dateParam, dateToCompare) {
  let minDiff = null;
  let mostAccurateDate = array[0];
  array.map((item) => {
    const diff = Math.abs(moment(dateToCompare).diff(item[dateParam], 'minutes', true));
    if (!minDiff || diff < minDiff) {
      minDiff = diff;
      mostAccurateDate = item
    }
  });
  return mostAccurateDate;
}

このソリューションには momentJS ライブラリが必要です

于 2020-04-03T16:30:36.683 に答える
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};
}
于 2012-08-06T10:36:30.607 に答える