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

C# 如何按类型对嵌套列表做顺序分组,合并相邻同类型节点

问题根因

你之前写的GroupBy是全局分组逻辑:会把整个序列里所有type值相同的元素,不管实际位置、不管是否相邻,全部归到同一组。这种逻辑既会打乱元素的原始顺序,也会把不连续出现的同类型节点(比如示例末尾单独出现的DEFAULT)错误合并到最开头的同类型分组里,完全达不到“只合并相邻连续同类型节点”的要求。

实现方案

不需要依赖框架自带的全局分组逻辑,通过顺序遍历实现连续相邻分组即可,核心逻辑非常简单:

  • 遍历原序列的每个节点,和结果集合中最后一个已存入的节点做类型对比
  • 如果类型一致,就把当前节点的primitives列表追加到最后一个节点的集合中
  • 如果类型不一致,就把当前节点作为新的独立项存入结果集合
  • 整个过程严格按照原序列顺序执行,不会打乱顺序,也不会跨位置合并不连续的同类型节点

可直接使用的实现代码

// 原输入的Type节点列表
List<Type> originalNodeList = GetOriginalInputData();
List<Type> mergedResult = new List<Type>();

foreach (var currentNode in originalNodeList)
{
    // 获取结果集合中最后一个已合并的节点
    var lastMergedNode = mergedResult.LastOrDefault();
    
    if (lastMergedNode == null)
    {
        // 第一个节点直接初始化存入结果
        mergedResult.Add(new Type
        {
            type = currentNode.type,
            primitives = new List<Primitive>(currentNode.primitives)
        });
    }
    else if (lastMergedNode.type == currentNode.type)
    {
        // 相邻节点类型一致,直接追加primitives内容
        lastMergedNode.primitives.AddRange(currentNode.primitives);
    }
    else
    {
        // 相邻节点类型不同,新增独立节点
        mergedResult.Add(new Type
        {
            type = currentNode.type,
            primitives = new List<Primitive>(currentNode.primitives)
        });
    }
}

可复用的通用扩展方法(可选)

如果后续经常需要处理连续相邻分组逻辑,可以封装通用扩展方法简化调用:

public static IEnumerable<List<T>> GroupByConsecutive<T>(
    this IEnumerable<T> source, 
    Func<T, T, bool> isSameGroup)
{
    using var enumerator = source.GetEnumerator();
    if (!enumerator.MoveNext()) yield break;

    var currentGroup = new List<T> { enumerator.Current };
    while (enumerator.MoveNext())
    {
        if (isSameGroup(currentGroup.Last(), enumerator.Current))
        {
            currentGroup.Add(enumerator.Current);
        }
        else
        {
            yield return currentGroup;
            currentGroup = new List<T> { enumerator.Current };
        }
    }
    yield return currentGroup;
}

调用方式简化为:

var mergedResult = originalNodeList
    .GroupByConsecutive((a, b) => a.type == b.type)
    .Select(group => new Type
    {
        type = group.First().type,
        primitives = group.SelectMany(node => node.primitives).ToList()
    })
    .ToList();
注意事项
  • 整个分组过程完全保留原始序列的先后顺序,最终生成的结构和你预期的示例完全匹配:两个相邻的DEFAULT节点合并、两个相邻的LOOP节点合并、末尾和LOOP相邻的DEFAULT节点单独成组
  • 你的实体类中已经给sequenceNo、startX、startY加了[YamlIgnore]特性,序列化YAML时会自动忽略这些字段,不需要额外做清洗
  • 最终YAML的缩进格式、单元素列表的展示规则,可根据你使用的Yaml序列化库(比如YamlDotNet)的配置调整,和分组逻辑本身无关

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.28 03:45:10