C# 如何检查我的日期范围是否完全被连续行覆盖?

C# 如何检查我的日期范围是否完全被连续行覆盖?,c#,C#,我需要检查此日期范围表是否完全覆盖了日期范围,该表按dFrom的升序排序,两者都是日期类型: dFrom dTo ----- ----- 10/01 10/03 10/05 10/08 10/08 10/09 10/09 10/12 10/13 10/18 10/15 10/17 10/19 10/24 范围A:10/01-10/14未完全涵盖,因为表中缺少10/04 范围B:10/10-10/20完全覆盖 我能想到的是,对于给定的日期范围,如a和B,检查表中是否包含每天:

我需要检查此日期范围表是否完全覆盖了日期范围,该表按dFrom的升序排序,两者都是日期类型:

dFrom  dTo
-----  -----
10/01  10/03
10/05  10/08
10/08  10/09
10/09  10/12
10/13  10/18
10/15  10/17
10/19  10/24
范围A:10/01-10/14未完全涵盖,因为表中缺少10/04

范围B:10/10-10/20完全覆盖

我能想到的是,对于给定的日期范围,如a和B,检查表中是否包含每天:

var dRangeFrom = rangeFrom.Date; // use "var" as C# has no date type
var dRangeTo = rangeTo.Date;
int DaysCovered = 0;
int HowManyDays = (dRangeTo - dRangeFrom).TotalDays()+1;
int StartFromRow = 0;
while (dRangeFrom <= dRangeTo)
{
  for (int i=StartFromRow; i<table.rows.count; i++)
  {
    if (table.rows[i]["dFrom"] > dRangeFrom)  // optimization 1: no need to continue.
      break;
    if (dRangeFrom >= table.rows[i]["dFrom"] && dRangeFrom <= table.rows[i]["dTo"])
    {
      DaysCovered++;
      StartFromRow = i;   // optimization 2: next day comparison simply starts from here 
      break;
    }
  }
  dRangeFrom.AddDays(1);
} 
if (DaysCovered == HowManyDays)
  Console.Write("Totally covered");
else
  Console.Write("NOT");

解决此问题的一种方法是编写一个helper方法,该方法获取范围内的所有日期:

public static List<DateTime> GetDaysCovered(DateTime from, DateTime to)
{
    var result = new List<DateTime>();

    for (var i = 0; i < (to.Date - from.Date).TotalDays; i++)
    {
        result.Add(from.Date.AddDays(i));
    }

    return result;
}
然后我们可以将表中的所有范围合并在一起,看看它们是否与我们试图覆盖的范围内的天数相匹配:

foreach (DataRow row in table.Rows)
{
    tableDates.AddRange(GetDaysCovered(
        row.Field<DateTime>("dFrom").Date, 
        row.Field<DateTime>("dTo").Date));
}

var rangeDates = GetDaysCovered(dRangeFrom, dRangeTo);

var missingDates = rangeDates
    .Where(rangeDate => !tableDates.Contains(rangeDate))
    .ToList();

if (missingDates.Any())
{
    Console.Write("These dates are not covered: ");
    Console.Write(string.Join(",", 
        missingDates.Select(date => date.ToShortDateString())));
}
else
{
    Console.Write("Totally covered");
}

一个简单的解决方案是检查范围内的每个日期是否包含在任何行中

var totallyCovered = true;

for (var date = rangeFrom.Date; date <= rangeTo.Date; date = date.AddDays(1)) 
{
    var covered = dates.Any(x => date >= x.dFrom && date <= x.dTo);

    if (!covered)
    {
        totallyCovered = false;
        break;
    }
}

if (totallyCovered)
{
    Console.WriteLine("Totally covered.");
}
else
{
    Console.WriteLine("No.");
}
这有点长而且难看,但谢天谢地,您可以将其放入一个LINQ查询中:

var dateRange = Enumerable.Range(0, 1 + rangeTo.Subtract(rangeFrom).Days)
          .Select(offset => rangeFrom.Date.AddDays(offset));
var totallyCovered = dateRange.All(d => dates.Any(x => d >= x.dFrom && d <= x.dTo)); 

注意:这具有O | range |*| rows |的时间复杂度,这可能太多了。要解决这个问题,您必须采用更复杂的数据结构,允许您在对数时间内查询范围,但由于您的原始示例也包含嵌套循环,因此我认为这是不必要的。

C没有日期类型,System.DateTime?var只是一个由编译器解析的隐式类型——它本身不是一个实际的类型。实际类型是DateTime。如果您将鼠标悬停在var上,它将在大多数IDEs.table中的工具提示中显示类型。代码示例中未定义dFrom和dTo。请发布一个说明问题的小样本。谢谢你的样本。由于LinQ实际上是foreach的幕后操作,在我的原始代码中添加了2个优化,所以性能还可以。另外,我相信任何阅读我的代码的人都更容易理解算法。@Jeb50我同意,只有当你有数十万行时,性能才会成为问题。很棒的示例。我一定会向你学习。随着优化添加到我的原始代码中,我相信性能和可读性将会提高。非常感谢。