>我有一个日期列表:
var dates = new List<DateTime>
{
new DateTime(2016, 01, 01),
new DateTime(2016, 02, 01),
new DateTime(2016, 03, 01),
new DateTime(2016, 04, 01),
new DateTime(2016, 05, 01)
};
现在给定一个特定的日期,一个"开始日期"。创建开始日期之后的日期列表以及之前的最后一个日期的最简单方法是什么?
即 - 如果我提供日期时间(2016, 03, 15),我需要返回
DateTime(2016, 03, 01),
DateTime(2016, 04, 01),
DateTime(2016, 05, 01)
它可以像查找最后一个"活动"日期一样简单,然后只使用该日期的位置。但我不确定如何在不使它变得非常复杂的情况下做到这一点。
如果您的列表已经排序,您可以使用二叉搜索:
var index = dates.BinarySearch(start);
// If the precise value isn't found, index will be the bitwise complement
// of the first index *later* than the target, so we need to subtract 1.
// But if there were no values earlier, we should start from 0.
if (index < 0)
{
index = Math.Max(~index - 1, 0);
}
return dates.Skip(index).ToList();
这假设日期是唯一的。如果有多个日期与start
相同,则不能保证它会找到第一个。如果这是一个问题,则需要向后搜索,直到找到第一个匹配项。
您尚未指定是否存在完全匹配项,是否要包含该匹配之前的日期。如果这样做,则需要稍微调整此代码。
不会让它变得复杂,如果我正确理解您的要求。您希望所有日期都位于 StartDate 之后,最后一个条目位于第一个匹配项之前(如果有)。然后我发现这是最简单、最易读的方法:
var results = dates.FindAll(x => x >= StartDate);
int index = dates.FindLastIndex(x => x < StartDate);
// there might be no match, if all the list is resulted
if (index >= 0)
results.Insert(0, dates[index]);
如果您更喜欢一种查询样式,则可以执行以下操作(我发现它不可读):
var results = dates.Where(x => x >= StartDate)
.Concat(dates.Where(x => x < StartDate)
.OrderByDescending(x => x).Take(1));
最后的选择,如果你喜欢花哨的方式:
int startIndex = dates.FindLastIndex(x=> x < StartDate);
startIndex = Math.Max(0, startIndex);
var results = dates.Skip(startIndex).ToList();
var partialResult = dates.Where(x => x >= date).ToList();
partialResult.Add(dates.Where(x => x < date).Max());
IList<DateTime> result = partialResult.OrderBy(x => x).ToList();