如何从列表中获取最接近的DateTime<;日期时间>;

本文关键字:lt 日期 gt 时间 DateTime 列表 最接近 获取 | 更新日期: 2024-09-24 17:33:34

假设我有最近的DateTime和所有可能日期的列表。我该如何有效地在列表中找到最接近去年日期的日期时间?

假设我的列表包括以下内容:

2014-03-07
2014-03-14
2014-03-21
2014-03-28
...
2015-03-06
2015-03-13
2015-03-20

我最近的日期是2015-03-20,但我想检索去年的日期,2014-03-21

这是我目前所拥有的,但如果去年的日期是休息一天(例如,我的时间段是每周存储的),它就不会起作用。

public DateTime LastYearDate()
{
    List<DateTime> times = GetAllDates();
    times.Sort();
    times.Reverse();
    DateTime currentDate = times.First();
    return times.Where(dt => dt == currentDate.AddYears(-1)).First();
}

我不确定我会用什么来递归计算最接近的日期,所以如果你对我应该采取的方向有任何想法(参考任何Linq函数来检查),那将不胜感激。

如何从列表中获取最接近的DateTime<;日期时间>;

只需根据列表中的日期和您要查找的日期之间的差异进行排序:

var dateToFind = currentDate.AddYears(-1);
times.OrderBy(t => (t - dateToFind).Duration).FirstOrDefault();

(两个日期之间的差异是TimeSpan的实例;Duration属性返回绝对值)

排序后,您可以使用二进制搜索来尝试找到完全匹配的结果。如果List<T>.BinarySearch返回一个非负数,那么您就知道找到了一个完全匹配的数字。否则,您可以应用逐位补码运算符来查找要插入该值的索引。然后,您需要检查该索引之前或索引处的值是否离目标更远。这样的东西:

var target = currentDate.AddYears(-1);
List<DateTime> times = GetAllDates();
if (times.Count == 0)
{
    // ??? Work out what you want to do here, e.g. throw an exception
}
times.Sort();
var index = times.BinarySearch(target);
if (index >= 0)
{
    return times[index];
}
int insertIndex = ~index;
// Handle boundary cases
if (insertIndex == 0)
{
    return times[0];
}
if (insertIndex == times.Count)
{
    return times[insertIndex - 1];
}
// Okay, two options - find the closest
var timeBefore = times[insertIndex - 1];
var timeAfter = times[insertIndex];
// TODO: Work out what you want to do if they're equidistant.
return target - timeBefore > timeAfter - target ? timeAfter : timeBefore;

话虽如此,spender对Thomas Levsque的回答的评论给出了一个非常简单的解决方案:

var target = currentDate.AddYears(-1);
List<DateTime> times = GetAllDates();
if (times.Count == 0)
{
    // ??? Work out what you want to do here, e.g. throw an exception
}
return times.OrderBy(t => (target - t).Duration).First();

注意,TimeSpan.Duration总是非负的;它类似于CCD_ 5,但对于CCD_。