查找最近时间的算法

时间:2019-05-08 06:41:02

标签: c# datetime

我有一个DateTime值列表,其中的日期包含小时和分钟:

List<DateTime> times = times = new List<DateTime>()
{
    new DateTime(2019, 01, 01, 17, 00, 00),
    new DateTime(2019, 01, 01, 18, 45, 00),
    new DateTime(2019, 01, 01, 19, 00, 00),
    new DateTime(2019, 01, 01, 19, 30, 00),
    new DateTime(2019, 01, 01, 22, 30, 00)
};

DateTime current = DateTime.Now;

我将它们全部放在一个ComboBox中,并且我想做出某种算法,因此当我加载表单时,它将检查当前时间并找到与当前时间最接近的值,然后选择包含以下内容的ComboBox项那个小时。

我该如何实现?我试图遍历所有它们并检查至少一个小时,但这似乎不起作用。有更聪明的方法吗?

例如:如果当前时间是17:32,它将选择17:00,因为那是最接近的时间。但是,如果当前时间是18:20,它将选择18:45,依此类推。

5 个答案:

答案 0 :(得分:5)

TicksMSDN)的DateTime属性进行比较。它可以看作是整个日期和时间戳的线性表示,并且可以排序。

做类似

comboBox.SelectedItem = times.OrderBy(t => Math.Abs(t.Ticks - current.Ticks)).First()

答案 1 :(得分:2)

您可以使用DateTime进行计算。现在,对于所有日期时间,按此进行排序并得出第一个结果。

times.OrderBy(m => Math.Abs((DateTime.Now - m).TotalMilliseconds)).First();

答案 2 :(得分:0)

您将必须选择一个DateTime实例,以最小化与当前时间的时间距离。您可以对IEnumerable<T>使用扩展方法,如下所示。

public static T ArgMin<T, R>(T t1, T t2, Func<T, R> f)
                where R : IComparable<R>
{
    return f(t1).CompareTo(f(t2)) > 0 ? t2 : t1;
}

public static T ArgMin<T, R>(this IEnumerable<T> Sequence, Func<T, R> f)
                where R : IComparable<R>
{
    return Sequence.Aggregate((t1, t2) => ArgMin<T, R>(t1, t2, f));
}

var iNow = DateTime.Now;
var iResult = times.ArgMin(iTime => Math.Abs((iTime - iNow).Ticks));

尽管非常通用,但此实现不涉及任何排序。

答案 3 :(得分:0)

您正在寻找ArgMax,它没有在标准 Linq 中实现,但可以通过Aggreagte

进行仿真
  List<DateTime> times = new List<DateTime>() {
    new DateTime(2019, 01, 01, 17, 00, 00),
    new DateTime(2019, 01, 01, 18, 45, 00),
    new DateTime(2019, 01, 01, 19, 00, 00),
    new DateTime(2019, 01, 01, 19, 30, 00),
    new DateTime(2019, 01, 01, 22, 30, 00),
  };

  DateTime toFind = new DateTime(2019, 5, 8, 18, 20, 0);

  var closestTime = times
    .Aggregate((best, item) => Math.Abs((item.TimeOfDay - toFind.TimeOfDay).Ticks) < 
                               Math.Abs((best.TimeOfDay - toFind.TimeOfDay).Ticks) 
       ? item 
       : best);

请注意,如果我们要找到最接近的时间,则必须删除日期部分-TimeOfDay。如果要计算日期部分,只需删除TimeOfDay-

  var closestDateAndTime = times
    .Aggregate((best, item) => Math.Abs((item - toFind).Ticks) < 
                               Math.Abs((best - toFind).Ticks) 
       ? item 
       : best);

答案 4 :(得分:0)

一种选择是使用MoreLinq的MinBy

var actualNow = DateTime.Now;
// set `current` up however you need it
var current = new DateTime(2019, 01, 01, actualNow.Hour, actualNow.Minute, actualNow.Minute, actualNow.Millisecond); // set this up however you need it
var min = times.MinBy(z => Math.Abs((current - z).Ticks)).First();

它避免了基于OrderBy的解决方案的内存压力(因为它避免了分配列表来存储整个times的列表)。

请注意,在使用此(或其他)解决方案之前,您可能需要检查times是否为空。如果您不想这样做,请考虑使用:

var min = times.MinBy(z => Math.Abs((current - z).Ticks)).Cast<DateTime?>().FirstOrDefault();

如果null为空,将返回default(DateTime)(而不是times或引发异常)。