如何使用LINQ知道一组句点中是否有任何重叠

时间:2011-04-02 08:24:30

标签: c# linq

我有一系列句点[FromDate, ToDate]

我想知道给定时期与集合中的时期之间是否有任何重叠。

我已经开始这样做了:

 // periodToCheck is the given item
 bool conflict = Periods.Any(p => ((p.FromDate >= periodToCheck.fromDate && 
                                    p.FromDate <= periodToCheck.toDate)
                                  ||
                                   (p.ToDate >= periodToCheck.fromDate && 
                                    p.ToDate <= periodToCheck.toDate))
                             );

它没有涵盖所有情况的问题,例如:

[2010.1.1], [2010.1.31]
[2010.1.5], [2010.1.6] // Is valid in the query in spite of it is not valid 
                       // (because there is intersection).

如果我讨论更多情况,我认为查询会变得更复杂。

我想知道你是否可以用最简单的有效方法帮助我。

问候。

4 个答案:

答案 0 :(得分:7)

相反地采用这种方式:如果检查日期的条件是&lt;从日期开始,或检查日期是从日期&gt;到目前为止。这是假设check.from&lt; = check.to。

Periods.Any(p => !(check.ToDate < p.FromDate || check.FromDate > p.ToDate));

或(在解开否定之后):

Periods.Any(p => check.ToDate >= p.FromDate && check.FromDate <= p.ToDate));

答案 1 :(得分:6)

如果FromDate <= ToDate对象的Period始终成立,您可以按如下方式定义帮助extension method OverlapsWith

public static bool OverlapsWith(this Period a, Period b)
{
    return !(b.ToDate <= a.FromDate || a.ToDate <= b.FromDate);
}

为了说明正在发生的事情,让我们看看ab之间没有重叠的两种情况:

//                         a
//                |-----------------|
//   |--------|                          |-----------|
//       b1                                    b2

您可以根据此图表检查上述条件。由于该图显示了不发生重叠的情况,但该方法确实应该测试重叠,因此需要否定该条件。它可以简化为以下内容:

           b.ToDate > a.FromDate && a.ToDate > b.FromDate

在LINQ查询中使用此方法时,很容易理解:

    Periods.Any(period => period.OverlapsWith(periodToCheck))

答案 2 :(得分:1)

您可能会发现following article有用,特别是TimePeriodIntersector类。

示例摘录:

public void TimePeriodIntersectorSample()
{
    TimePeriodCollection periods = new TimePeriodCollection();

    periods.Add( new TimeRange( new DateTime( 2011, 3, 01 ), new DateTime( 2011, 3, 10 ) ) );
    periods.Add( new TimeRange( new DateTime( 2011, 3, 05 ), new DateTime( 2011, 3, 15 ) ) );
    periods.Add( new TimeRange( new DateTime( 2011, 3, 12 ), new DateTime( 2011, 3, 18 ) ) );

    periods.Add( new TimeRange( new DateTime( 2011, 3, 20 ), new DateTime( 2011, 3, 24 ) ) );
    periods.Add( new TimeRange( new DateTime( 2011, 3, 22 ), new DateTime( 2011, 3, 28 ) ) );
    periods.Add( new TimeRange( new DateTime( 2011, 3, 24 ), new DateTime( 2011, 3, 26 ) ) );

    TimePeriodIntersector<TimeRange> periodIntersector = 
                    new TimePeriodIntersector<TimeRange>();
    ITimePeriodCollection intersectedPeriods = periodIntersector.IntersectPeriods( periods );

    foreach ( ITimePeriod intersectedPeriod in intersectedPeriods )
    {
        Console.WriteLine( "Intersected Period: " + intersectedPeriod );
    }
    // > Intersected Period: 05.03.2011 - 10.03.2011 | 5.00:00
    // > Intersected Period: 12.03.2011 - 15.03.2011 | 3.00:00
    // > Intersected Period: 22.03.2011 - 26.03.2011 | 4.00:00
} // TimePeriodIntersectorSample

答案 3 :(得分:0)

2个具有共同日期的期间,例如期间1的ToDate和期间2的FromDate是相同的,计算在交叉点?

如果是,那么对您的查询进行一点修改,只需检查一个句点的日期,如果它们在一个检查周期内,就好像其中一个日期属于一个句点,那么就有交集:

bool conflict = Periods.Any(p => ((p.FromDate >= periodToCheck.fromDate && 
                                    p.ToDate <= periodToCheck.fromDate)
                                  ||
                                   (p.FromDate >= periodToCheck.toDate && 
                                    p.ToDate <= periodToCheck.toDate))
                             );