根据事件值按时间顺序过滤出事件



问题已编辑。看到评论

我有以下有序(启动/停止)事件列表,这些事件由多个由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

开始之后应该有一个停止或什么都没有,反之亦然。

这是一个典型的缺口和岛屿问题,对吗?让我们将岛屿号添加到初始数据集中。除非我错了,否则我们应该这样结束:

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函数来完成这一点,而是通过编写一个快速的" lag"你可以用一条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;
}
}
}

为了回答这个问题,我创建了一个类来保存数据(您应该已经有了):

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

最新更新