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

C#快速提取List连续值:鼠标轨迹数据分组优化需求

优雅处理鼠标轨迹数据分组的LINQ方案

嘿,这个处理鼠标轨迹分组的需求我太熟悉了!之前做类似的交互分析工具时也踩过遍历写法的坑,代码冗余还容易写错边界条件。用LINQ结合相邻分组的技巧,能让代码优雅很多,而且可读性和维护性都能上来。

首先,先明确我们要解决的核心问题:把连续相同ButtonsDownFlag的鼠标事件分成组——原生LINQ的GroupBy是按值全局分组,没法区分连续的序列,所以我们先写一个通用的相邻分组扩展方法,这个方法以后处理其他连续序列场景也能复用:

public static IEnumerable<IEnumerable<T>> GroupAdjacent<T>(this IEnumerable<T> source, Func<T, T, bool> predicate)
{
    using var enumerator = source.GetEnumerator();
    if (!enumerator.MoveNext()) yield break;
    
    var currentGroup = new List<T> { enumerator.Current };
    while (enumerator.MoveNext())
    {
        if (predicate(currentGroup.Last(), enumerator.Current))
        {
            currentGroup.Add(enumerator.Current);
        }
        else
        {
            yield return currentGroup;
            currentGroup = new List<T> { enumerator.Current };
        }
    }
    yield return currentGroup;
}

接下来,我们基于这个扩展方法,结合你的需求拆分出两个目标列表:

1. 提取拖拽操作列表(连续≥2个ButtonsDownFlag=1的组)

我们筛选出所有连续Flag=1且长度≥2的组,然后把组内每个元素的TimeStamp替换为组首的时间戳:

var dragOperations = mouseInfos
    .GroupAdjacent((prev, curr) => prev.ButtonsDownFlag == curr.ButtonsDownFlag)
    .Where(group => group.First().ButtonsDownFlag == 1 && group.Count() >= 2)
    .SelectMany(group => 
        group.Select(item => new 
        { 
            TimeStamp = group.First().TimeStamp,
            item.PosX,
            item.PosY
        })
    )
    .ToList();

2. 提取点击操作列表(单独非0Flag项,含连续右键)

这里需要区分两种情况:

  • 对于Flag=1的组,只有当组长度为1时才视为点击;
  • 对于其他非0Flag(比如右键2、双按键3),不管是否连续,每个元素都视为单独点击:
var clickOperations = mouseInfos
    .GroupAdjacent((prev, curr) => prev.ButtonsDownFlag == curr.ButtonsDownFlag)
    .Where(group => group.First().ButtonsDownFlag != 0)
    .SelectMany(group => 
        group.First().ButtonsDownFlag == 1
            ? group.Where(_ => group.Count() == 1).Select(item => new { item.PosX, item.PosY, item.ButtonsDownFlag })
            : group.Select(item => new { item.PosX, item.PosY, item.ButtonsDownFlag })
    )
    .ToList();

测试示例数据

用你给出的示例数据验证:

  • 拖拽列表会得到:(t2,x2,y2), (t2,x3,y3), (t7,x7,y7), (t7,x8,y8), (t7,x9,y9),完全符合预期;
  • 点击列表会得到:(x5,y5,1), (xb,yb,2), (xd,yd,2), (xe,ye,2),也和需求一致。

一些注意事项

  • 因为你的MouseInfo类中TimeStamp是readonly的,所以我们用匿名类型来存储修改后的数据,如果需要返回MouseInfo实例,可以添加一个带参数的构造函数来创建新对象;
  • 这个方案的时间复杂度是O(n),和遍历写法效率一致,但代码更简洁,逻辑更清晰;
  • 扩展方法GroupAdjacent是通用的,可以放在你的工具类中,后续处理任何连续序列分组都能直接用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:10:01