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
相关产品推荐
相关产品推荐

