C#重构JSON对象:将父带子层级结构转为按子项聚合父项的格式
问题根因
你单ID匹配的逻辑本身没有问题,问题出在把这个全量扫描的逻辑嵌套在child ID的循环里:每匹配一个child ID就要把原始集合完整扫描一遍,整体时间复杂度是O(n²)。当数据量上来后,重复扫描的耗时、临时集合分配的内存会快速上涨,自然会出现卡顿,甚至因为内存压力过大导致进程崩溃。
最优实现方案
核心思路是做单次线性扫描的分组聚合,全程只遍历一次原始集合,就可以把所有父项按所属child完成挂载,时间复杂度降到O(n),效率会比循环匹配高一个数量级以上,完全不会出现大数据量下的卡顿问题。
步骤1:定义对应结构的实体类
先匹配原始反序列化结构和最终输出结构,避免冗余字段带来的额外内存开销:
// 对应原始JSON的父项结构 public class RawParentItem { public string name { get; set; } public int id { get; set; } public RawChildItem child { get; set; } } // 对应原始JSON的子项结构 public class RawChildItem { public string name { get; set; } public int id { get; set; } } // 对应最终输出的分组结果结构 public class GroupedChildOutput { public string name { get; set; } public int id { get; set; } public List<RawParentItem> parents { get; set; } }
步骤2:单次扫描完成分组重构
直接用LINQ的GroupBy能力,一次遍历生成目标结构,不需要嵌套循环:
// 按child的id作为分组依据,全程无额外全量查询 var result = deserializedJsonData .GroupBy( keySelector: sourceItem => sourceItem.child.id, resultSelector: (childId, itemsUnderChild) => { // 同个child id下的子项元数据完全一致,直接从分组元素中取,不需要额外查询 var childInfo = itemsUnderChild.First().child; return new GroupedChildOutput { name = childInfo.name, id = childId, // 分组时直接裁剪不需要的child字段,只保留父项需要的name和id parents = itemsUnderChild.Select( i => new RawParentItem { name = i.name, id = i.id } ).ToList() }; } ) .ToList();
注意:如果实体的相等判断配置不影响分组结果,也可以直接按child对象本身作为分组key,写法会更简洁。
不要为了分组单独先枚举所有child ID列表,再循环做匹配,这种写法会完全抵消分组的效率优势。
效果说明
- 处理10万条原始数据的耗时基本在几毫秒以内,完全不会出现之前循环遍历匹配的卡顿问题
- 从根本上避免了重复扫描、临时集合频繁分配带来的GC压力,哪怕数据量更大也不会出现进程崩溃的问题
内容的提问来源于stack exchange,提问作者Stefan
相关产品推荐
相关产品推荐

