使用LINQ查找重叠的时间段(事件)

tes*_*ing 8 c# linq

我有一个事件列表,现在我想找出哪些事件重叠.您可以在下面找到我目前拥有的代码,但我遇到的问题是,搜索到的项目也包含在列表中.

List<SomeEventObject> overlappingEvents = new List<SomeEventObject>();
foreach (SomeEventObject eventItem in EventList)
{
    bool overlapping = false;
    foreach (SomeEventObject anotherEventItem in EventList)
    {
        if (eventItem.StartDate <= anotherEventItem.EndDate &&
            eventItem.EndDate >= anotherEventItem.StartDate)
        {
            overlapping = true;
            overlappingEvents.Add(anotherEventItem);
        }
    }

    if (overlapping)
        overlappingEvents.Add(eventItem);
}
Run Code Online (Sandbox Code Playgroud)

我需要创建一个没有搜索项目的新列表.因此我问是否有一个很好的LINQ表达式可以为我处理.这是我想到的一些伪代码:

EventList.Where(e => 
                eventItem.StartDate <= e.EndDate && 
                eventItem.EndDate >= e.StartDate);
Run Code Online (Sandbox Code Playgroud)

在这种情况下,eventItem当然不存在.

结果我认为我需要两个列表:一个具有重叠事件,一个具有非重叠事件.但.Except()如果我有重叠的事件列表,这应该是可能的.

编辑:

我创建了一个dotnetfiddle,以便人们可以玩它.一个重要的问题是重叠算法.

活动1:
StartDate:今天,10
:00 EndDate:今天,10:05

事件2:
StartDate:今天,10
:05 EndDate:今天,10:10

如果您向用户提供此信息,则不会重叠.所以我要修改我的算法.

Eni*_*ity 6

我会这样做:

var overlappingEvents =
(
    from e1 in EventList
    from e2 in EventList
    where e1 != e2
    where e1.StartDate <= e2.EndDate
    where e1.EndDate >= e2.StartDate
    from e in new [] { e1, e2 }
    select e
).ToList();
Run Code Online (Sandbox Code Playgroud)

我认为这应该很简单。


根据评论,这个版本只返回一个EventList元素一次,不管它参与了多少重叠。

var overlappingEvents =
(
    from e1 in EventList
    where EventList
        .Where(e2 => e1 != e2)
        .Where(e2 => e1.StartDate <= e2.EndDate)
        .Where(e2 => e1.EndDate >= e2.StartDate)
        .Any()
    select e1
).ToList();
Run Code Online (Sandbox Code Playgroud)

也可以写成:

var overlappingEvents =
    EventList
        .Where(e1 =>
            EventList
                .Where(e2 => e1 != e2)
                .Where(e2 => e1.StartDate <= e2.EndDate)
                .Where(e2 => e1.EndDate >= e2.StartDate)
                .Any())
        .ToList();
Run Code Online (Sandbox Code Playgroud)

根据进一步的评论,这里是如何配对事件:

var overlappingEvents =
(
    from e1 in EventList
    from e2 in EventList
    where e1 != e2
    where e1.StartDate <= e2.EndDate
    where e1.EndDate >= e2.StartDate
    select new [] { e1, e2 }
).ToList();
Run Code Online (Sandbox Code Playgroud)

现在overlappingEvents是一个数组列表 -List<SomeEventObject[]>而不是List<SomeEventObject>. 该数组包含重叠事件。


jno*_*ovo 2

我会尝试这样的事情:

var searchedFor = EventList.First(); // Replace by the proper one

var overlapping = EventList.Where(e => e != searchedFor && 
    EventList.Any(ev => e != ev && ev.StartDate <= e.EndDate && ev.EndDate >= e.StartDate))

// Alternatively with Except

var overlapping = EventList.Except(new[] { searchFor }).Where(e => 
    EventList.Any(ev => e != ev && ev.StartDate <= e.EndDate && ev.EndDate >= e.StartDate))
Run Code Online (Sandbox Code Playgroud)

对于非重叠,您只需EventList使用以下方法过滤重叠事件Except

var nonOverlapping = EventList.Except(overlappingEvents);
Run Code Online (Sandbox Code Playgroud)

我不知道你的情况SomeEventObject,但你可能需要通过一些比较来改变不平等比较Id

有一个关于检测 C# 中重叠周期的非常好的问答,您可能想研究一下。为了方便起见,您还可以按如下方式分解支票:

Func<SomeEventObject, SomeEventObject, bool> areOverlapped = (e1, e2) => 
    e1.StartDate <= e2.EndDate && e1.EndDate >= e2.StartDate;

var overlapping = EventList.Where(e => e != searchedFor && 
    EventList.Any(ev => e != ev && areOverlapped(e, ev)));
Run Code Online (Sandbox Code Playgroud)