【问题标题】:Linq Overlapped date range checking in single collection单个集合中的 Linq 重叠日期范围检查
【发布时间】:2018-07-06 07:31:19
【问题描述】:
Class TimeRange{
  private DateTime StartDate{get; set;}
  private DateTime EndDate{get; set;}
}

List<TimeRange> TimeRangeList = new List<TimeRange>(){
  new TimeRange(){StartDate = new DateTime(2050, 1, 1), 
                    EndDate = new DateTime(2050, 1, 10)},
  new TimeRange(){StartDate = new DateTime(2050, 2, 1), 
                    EndDate = new DateTime(2050, 2, 10)},
  //This item will triggered the overlap validation failed
  new TimeRange(){StartDate = new DateTime(2050, 1, 5),
                    EndDate = new DateTime(2050, 1, 9)},
                              },
}

所以在我检查了similar topic 之后,我仍然无法弄清楚检查重叠日期范围的算法。

这在SQL中是相当简单的,根据Checking for date overlap across multiple date range objects

我只需要像这样比较两个日期范围

SELECT COUNT(*)
FROM Table1
WHERE Table1.StartDate < 'endCheckDate'
AND Table1.EndDate > 'startCheckDate'

我发现在Linq中很难做到,我们如何比较一个集合中的所有项目?因为我们可以像比较两个列表一样在循环集合中使用 foreach,但是它在 select 中是如何工作的?

其实我正在做这样的事情

for (int i = 0; i < TimeRangeList .Count(); ++i)
{
        var item = TimeRangeList[i];                    
        for (int y = i + 1; y < TimeRangeList.Count(); ++y)
        {
                var item2 = TimeRangeList[y];

                if (IsOverLapped(item, item2))
                {
                    // this is overlapped
                };
        }
}

private bool IsOverLapped(dynamic firstObj, dynamic secondObj)
{
        return secondObj.StartDate <= firstObj.EndDate && firstObj.StartDate <= secondObj.EndDate;
}

没有循环有没有更优雅的方法?

所以我的问题是我们如何通过 linq 比较每个项目本身的单个列表?

【问题讨论】:

  • SQL 检查固定的开始/结束时间段。不清楚你想在 Linq 中做什么,对项目进行分组?
  • 既然已经提供了示例列表,为什么不提供编译代码?例如,没有接受字符串的 DateTime 构造函数。
  • 你可以使用这个 TimePeriod 库:codeproject.com/Articles/168662/Time-Period-Library-for-NET 它还有一个 TimeRange 类和 OverlapsWith 或 IntersectsWith 等方法。
  • @bommelding 很抱歉造成混淆,如果发生重叠,我实际上是在做 ModelState.AddModelError() 。在这种情况下,它只是返回一个布尔值。我更新了我的示例列表,假设必须有一个固定的检查时间,只是我应该确定它在 linq 中是如何工作的
  • @bommelding TimeRangeList.Any( /* 日期时间重叠检查*/ );我将其放入 validation 的规则中

标签: c# linq


【解决方案1】:

一个简单的蛮力想法:

bool overlap = TimeRangeList
    .Any(r => TimeRangeList
         .Where(q => q != r)             
         .Any(q => q.EndDate >= r.StartDate && q.StartDate <= r.EndDate) );

【讨论】:

  • 就像一个魅力!但是这个 linq 是如何工作的?让我再测试一下,非常感谢您的帮助
  • 是否存在与 any other 元素重叠的 any 元素? other部分由q != r实现。
  • 但最后一个条件当然还不正确,现在编辑。
【解决方案2】:

如果我查看您的 SQL 代码,您似乎有一个 Table1 对象,它是一系列相似对象,比如说 Table1Row 类。每个Table1Row 至少有两个日期时间属性,一个StartDate 和一个EndDate。此外,您还有两个 DateTime 对象:startCheckDateendCheckDate

您想计算Table1StartDate 小于startCheckDateEndDate 大于endCheckDate 的所有元素

写成IQueryable的扩展函数:

public static int CountOverlapping(this IQueryable<Table1Row> table1,
    DateTime startCheckDate,
    DateTime endCheckDate)
{
    return table1
        .Where (row => row.StartDate < startCheckDate && row.EndDate > endCheckDate)
        .Count();
}

用法:

DateTime startCheckDate = ...
DateTime endCheckDate = ...
IQueryable<Table1Row> table1 = ...
int nrOfOverlapping = table1.CountOverlapping(startCheckDate, endCheckDate);

简单的祝你好运?

【讨论】:

  • 谢谢,只是我正在寻找一种方法来要求列表按时间属性比较自身,它是动态的和通用的。在您提供的方法中,一个可能循环两次,假装它有两个列表并调用该方法,这不是我真正想要的。
  • 实际上@bommelding 发表了他的想法,我认为这应该是准确的答案,但似乎他只是删除了答案,如果他倒带它会给他功劳。
  • 为什么你认为一个Where后跟一个Count需要枚举两次?
  • 对不起,如果我在我的主题中混淆了你。但在这种情况下,它必须是通过列表对每个项目本身进行比较,而不是在给定的日期范围内。所以我们不要将它们作为参数输入。您的示例假设我有一个输入日期作为检查点。
猜你喜欢
  • 1970-01-01
  • 2011-02-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多