根据事件的价值按时间顺序过滤掉事件

Filter out events order by time based on their value

问题已被编辑。见评论。更改以斜体显示。

我有以下有序 (start/stop) 事件列表,这些事件由 由 ID 标识的多个物理设备生成。为简单起见,仅显示一台设备的数据

Date       Hour     ID Event           IsStart
18/10/2021 10:35:22 1  DeviceConnected  True
18/10/2021 10:20:10 1  DeviceConnected  True
18/10/2021 10:12:20 1  DeviceConnected  False
18/10/2021 10:12:19 1  DeviceConnected  False
18/10/2021 08:24:14 1  DeviceConnected  True

在给定的时间段内(通常是 24 小时),我不能连续启动或停止两次或多次。我需要删除“重复项”。

在上面的示例中,这意味着在使用 linq 应用过滤器之后:

Date       Hour     ID Event           IsStart
18/10/2021 10:20:10 1  DeviceConnected  True
18/10/2021 10:12:19 1  DeviceConnected  False
18/10/2021 08:24:14 1  DeviceConnected  True

开始后应该停止或什么都不停止,反之亦然。

这是一个典型的 Gaps-and-Islands 问题,对吧?让我们将岛屿编号添加到初始数据集中。除非我错了,否则我们应该以这样的方式结束:

Date       Hour     ID Event           IsStart Island
18/10/2021 10:35:22 1  DeviceConnected  True    3
18/10/2021 10:20:10 1  DeviceConnected  True    3
18/10/2021 10:12:20 1  DeviceConnected  False   2
18/10/2021 10:12:19 1  DeviceConnected  False   2
18/10/2021 08:24:14 1  DeviceConnected  True    1

我可以用 Linq 做到这一点吗?如果是这样的话,我应该只能保留岛上的第一条记录了。

我认为您无法使用开箱即用的 LINQ 函数来完成此操作,但通过编写快速“滞后”扩展方法,您可以使用单个 LINQ 语句来完成此操作:

public static class EnumerableExtensions 
{
    public static IEnumerable<TResult> Lag<TSource, TResult>(
        this IEnumerable<TSource> source,
        TSource defaultLagValue,
        Func<TSource, TSource, TResult> resultSelector
    )
    {
        TSource lagValue = defaultLagValue;
        foreach (var item in source)
        {
            yield return resultSelector(item, lagValue);
            lagValue = item;
        }
    }
}

然后为了这个答案的目的,我正在创建一个 class 来保存数据(你应该已经有):

public class Event
{
    public DateTime Date { get; set; }
    public string Name { get; set; }
    public bool IsStart { get; set; }
}

那么,运行它是这样的:

var data = new List<Event>();
data.Add(new Event { Date = new DateTime(2021, 10, 18, 10, 35, 22), Name = "DeviceConnected", IsStart = true  });
data.Add(new Event { Date = new DateTime(2021, 10, 18, 10, 20, 10), Name = "DeviceConnected", IsStart = true  });
data.Add(new Event { Date = new DateTime(2021, 10, 18, 10, 12, 20), Name = "DeviceConnected", IsStart = false });
data.Add(new Event { Date = new DateTime(2021, 10, 18, 10, 12, 19), Name = "DeviceConnected", IsStart = false });
data.Add(new Event { Date = new DateTime(2021, 10, 18,  8, 24, 14), Name = "DeviceConnected", IsStart = true  });

List<Event> filteredData = data
    .OrderBy(e => e.Date)
    .Lag(null, (e, lag) => new {
        Event = e,
        PreviousItem = lag,
    })
    .Where(x => x.PreviousItem == null || x.Event.IsStart != x.PreviousItem.IsStart)
    .Select(x => x.Event)
    .OrderByDescending(e => e.Date)
    .ToList();

之后,filteredData 应该包含与此类似的预期输出:

Date       Hour     Event           IsStart
18/10/2021 10:20:10 DeviceConnected True
18/10/2021 10:12:19 DeviceConnected False
18/10/2021 08:24:14 DeviceConnected True