You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Linq处理设备启停事件连续重复项(Gaps-and-Islands问题)

实现方案

你描述的确实是典型的Gaps-and-Islands场景,完全可以用LINQ实现。
首先假设你的事件实体类定义如下:

public class DeviceEvent
{
    public DateTime Date { get; set; }
    public int ID { get; set; }
    public string Event { get; set; }
    public bool IsStart { get; set; }
}

1. 给事件添加岛屿编号(和你预期的编号规则完全匹配)

核心逻辑是先按时间升序遍历,判断当前事件和上一个事件的IsStart值是否变化,变化则岛屿编号+1,最后再按时间降序返回即可:

// 原始事件列表
List<DeviceEvent> originalEvents = 获取你的原始数据();

// 生成带岛屿编号的结果
var eventsWithIsland = originalEvents
    // 先按时间升序排序(从早到晚遍历,保证编号从最早的事件开始递增)
    .OrderBy(e => e.Date)
    // 生成岛屿编号
    .Select(((e, index) => 
    {
        // 闭包存储上一个事件的状态和当前编号
        if (index == 0)
        {
            lastIsStart = e.IsStart;
            currentIslandId = 1;
        }
        else if (e.IsStart != lastIsStart)
        {
            currentIslandId++;
            lastIsStart = e.IsStart;
        }
        return new
        {
            e.Date,
            e.ID,
            e.Event,
            e.IsStart,
            Island = currentIslandId
        };
    }))
    // 按时间降序排列,和你示例的输出顺序一致
    .OrderByDescending(e => e.Date)
    .ToList();

// 闭包变量定义
bool lastIsStart;
int currentIslandId;

2. 去重得到最终结果

按岛屿编号分组,取每个分组里时间最早的记录即可,和你给出的预期结果完全匹配:

var deduplicatedEvents = eventsWithIsland
    .GroupBy(e => e.Island)
    // 取每个岛屿时间最早的记录
    .Select(g => g.OrderBy(e => e.Date).First())
    // 按时间降序排列输出
    .OrderByDescending(e => e.Date)
    .ToList();

3. 多设备兼容方案

如果是多设备混合的数据集,先按设备ID分组,每个设备单独处理即可:

var multiDeviceResult = originalEvents
    // 按设备ID分组,不同设备互不影响
    .GroupBy(e => e.ID)
    .SelectMany(g =>
    {
        bool deviceLastIsStart = default;
        int deviceCurrentIslandId = 1;
        return g
            .OrderBy(e => e.Date)
            .Select((e, index) =>
            {
                if (index == 0)
                {
                    deviceLastIsStart = e.IsStart;
                    deviceCurrentIslandId = 1;
                }
                else if (e.IsStart != deviceLastIsStart)
                {
                    deviceCurrentIslandId++;
                    deviceLastIsStart = e.IsStart;
                }
                return new
                {
                    e.Date,
                    e.ID,
                    e.Event,
                    e.IsStart,
                    Island = deviceCurrentIslandId
                };
            });
    })
    .OrderByDescending(e => e.Date)
    .ToList();

注意:以上方案为内存侧LINQ to Objects实现,如果要对接数据库操作,需要先将对应时间范围内的设备数据加载到内存再执行上述逻辑。

内容的提问来源于stack exchange,提问作者anon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 18:27:06