在输入日期之前的列表中查找最近的日期

Finding closest date in a list before the input date

我找到了这段用于查找日期范围内最接近日期的代码

    var inputDate = UserInputDate;
    List<DateTime> allDates = new List<DateTime>();
    allDates.add(date1);
    allDates.add(date2);
    allDates.add(date3);

    var closestDate = inputDate >= allDates.Last()
        ? allDates.Last()
        : inputDate <= allDates.First()
            ? allDates.First()
            : allDates.First(d => d >= inputDate);

然而,此代码会找到最晚于输入日期的日期。

我需要的是输入日期之前最接近的日期

老实说,我不明白这段代码,而且 我尝试将 >= 更改为 <= 并将 .Last 更改为 .First 但它没有按照我想要的方式工作

我会通过构建小于输入日期的所有项目的过滤列表来解决这个问题,然后取最大值:

var closestDate = allDates.Where(x => x < inputDate).DefaultIfEmpty().Max();

Where 将过滤为仅保留所有小于 inputDate 的日期,然后 Max 将选择最大的日期。

如果您认为列表可能为空,您可以在 Max 之前使用 DefaultIfEmpty()(如果列表为空,结果将是 default(DateTime)。您也可以将其拆分:

var possibleDates = allDates.Where(x => x < inputDate);
if (possibleDates.Any())
{
    var closestDate = possibleDates.Max();
}

但是,如果allDates已经在内存中排序,那么你可以简单地做:

var closestDate = allDates.TakeWhile(x => x < inputDate).Last();

TakeWhile 也会选择小于 inputDate 的元素,但在找到更大的元素后停止。 (如果它是预排序的,这是有道理的。)

同样,要处理空列表,您可以使用 LastOrDefault 或与上面相同的 Any 模式。

将它们降序排列,然后取符合您条件的第一个:

var closest = allDates.OrderByDescending(x => x).First(x => x <= inputDate);

如果 列表已排序,您可以使用 BinarySearch 函数,其中 returns

The zero-based index of item in the sorted List, if item is found; otherwise, a negative number that is the bitwise complement of the index of the next element that is larger than item or, if there is no larger element, the bitwise complement of Count.

int pos = allDates.BinarySearch(inputDate);
if (pos < 0)
    pos = ~pos - 1;

var closestDate = allDates[pos];

为了解释你问题中的代码,它基本上是这样说的

如果您要搜索的项目早于列表中的最后一个日期,则取最后一个项目

var closestDate = inputDate >= allDates.Last()
? allDates.Last()

否则如果输入日期低于第一项,取第一项

: inputDate <= allDates.First()
    ? allDates.First()

否则取大于或等于输入日期的第一项

: allDates.First(d => d >= inputDate);

如果您只想反转问题的逻辑,您需要最后一行来获取小于您输入的 last 项。请注意,这依赖于仍在排序的列表:

var closestDate = inputDate >= allDates.Last()
    ? allDates.Last()
    : inputDate <= allDates.First()
        ? allDates.First()
        : allDates.Last(d => d <= inputDate);