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

Eth*_*ong 1 c# linq datetime list

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

说我的清单包括以下内容:

2014-03-07
2014-03-14
2014-03-21
2014-03-28
...
2015-03-06
2015-03-13
2015-03-20
Run Code Online (Sandbox Code Playgroud)

我最近的约会时间是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();
}
Run Code Online (Sandbox Code Playgroud)

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

Tho*_*que 7

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

var dateToFind = currentDate.AddYears(-1);
times.OrderBy(t => (t - dateToFind).Duration).FirstOrDefault();
Run Code Online (Sandbox Code Playgroud)

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

  • @EthanDeLong命令由`Math.Abs​​((t-dateToFind).TotalDays)`代替 (3认同)

Jon*_*eet 5

排序后,您可以使用二分搜索来尝试找到完全匹配的内容。如果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;
Run Code Online (Sandbox Code Playgroud)

话虽如此,斯彭德对托马斯·莱维斯克的回答的评论给出了一个非常简单的解决方案:

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();
Run Code Online (Sandbox Code Playgroud)

请注意TimeSpan.Duration始终为非负数;这就像Math.Abs但为了TimeSpan价值观。