我有一个数组,里面有几天。每天都是一个对象,例如:
{day_year: "2012", day_month: "08", day_number: "03", day_name: "mon"}
我还使用以下方法为每个日期对象添加了一个timestamp属性:
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月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};
}
答案 0 :(得分:18)
您可以轻松地将sort
function与自定义比较器功能一起使用:
// 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
之前或之后的结果,您可以filter数组:
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);
答案 1 :(得分:9)
如果使用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 */
答案 2 :(得分:6)
Zeta's答案非常好,但如果你想知道最近的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]]]);
答案 3 :(得分:1)
这是我们使用的:
此函数在 array 中查找具有与 dateToCompare 最接近的日期(名为 dateParam )的项目。
对于每个 item [ 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库
答案 4 :(得分:1)
您可以这样尝试
var dates = [
'July 16, 1995 03:24:00',
'Aug 18, 1995 03:24:00',
'August 19, 1995 03:24:00',
'September 17, 1995 03:24:00',
'September 14, 1995 03:24:00',
'August 18, 1995 03:24:00',
'July 16, 1995 03:24:00',
'December 15, 1995 03:24:00',
'July 13, 1995 03:24:00',
]
var temp = dates.map(d => Math.abs(new Date() - new Date(d).getTime()));
var idx = temp.indexOf(Math.min(...temp));
console.log(dates[idx]);
答案 5 :(得分: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};
}