如何从List <datetime> </datetime>获取最接近的DateTime

时间:2015-03-02 18:44:42

标签: c# linq list datetime

假设我有最新的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函数来检查),那将不胜感激。< / p>

2 个答案:

答案 0 :(得分:7)

只需按照列表中的日期与您要查找的日期之间的差异进行排序:

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

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

答案 1 :(得分:4)

在排序后,您可以使用二进制搜索来尝试查找完全匹配。如果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 Levesque的回答给出了一个非常简单的解决方案:

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始终为非负数;它与Math.Abs相似,但适用于TimeSpan值。