根据事件的价值按时间顺序过滤掉事件
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
问题已被编辑。见评论。更改以斜体显示。
我有以下有序 (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