C#中合并列表内同LineId对象的最优实现方案
问题解答
1. 性能提升核心思路
原实现的最大瓶颈是嵌套循环带来的O(n²)时间复杂度,再加上重复的字符串拼接、频繁的数值类型转换,处理大规模数据时效率极低。提升性能的关键方向:
- 用哈希表(
Dictionary)做分组,将时间复杂度降到O(n) - 用
StringBuilder替代直接字符串拼接,减少内存分配 - 避免重复的类型转换,尽量提前将字符串数值转成数值类型计算
- 不要修改原集合元素,避免产生副作用
2. 更优实现方式
方式一:Linq GroupBy实现(简洁易读)
利用Linq的分组功能,代码简洁且可读性强,适合大部分场景:
using System.Globalization; using System.Linq; var mergedLines = lines .GroupBy(line => line.LineId) .Select(group => { var firstLine = group.First(); // 求和AccountingTotal decimal totalAccounting = group.Sum(line => line.AccountingTotal ?? 0); // 求和Price(先转decimal计算,再格式化) decimal totalPrice = group.Sum(line => decimal.Parse(line.Price, CultureInfo.InvariantCulture)); // 求和Total decimal totalTotal = group.Sum(line => decimal.Parse(line.Total, CultureInfo.InvariantCulture)); // 拼接Description var descBuilder = new StringBuilder(); foreach (var line in group) { if (descBuilder.Length > 0) descBuilder.Append(" | "); descBuilder.Append(line.Description); } // 拼接MergedId string mergedId = string.Join("|", group.Select(l => l.Id)); return new Line { Id = firstLine.Id, MergedId = mergedId, AccountingTotal = Math.Round(totalAccounting, 2), Description = descBuilder.ToString(), Price = totalPrice.ToString("F2", CultureInfo.InvariantCulture), Total = totalTotal.ToString("F2", CultureInfo.InvariantCulture), LineId = group.Key }; }) .ToList();
方式二:手动Dictionary分组(性能最优)
如果数据量达到百万级以上,手动用Dictionary分组可以减少Linq的额外开销,性能更优:
using System.Collections.Generic; using System.Globalization; var lineDict = new Dictionary<string, Line>(); foreach (var line in lines) { if (lineDict.TryGetValue(line.LineId, out var existingLine)) { // 累加AccountingTotal existingLine.AccountingTotal = Math.Round((existingLine.AccountingTotal ?? 0) + (line.AccountingTotal ?? 0), 2); // 累加Price existingLine.Price = (decimal.Parse(existingLine.Price, CultureInfo.InvariantCulture) + decimal.Parse(line.Price, CultureInfo.InvariantCulture)) .ToString("F2", CultureInfo.InvariantCulture); // 累加Total existingLine.Total = (decimal.Parse(existingLine.Total, CultureInfo.InvariantCulture) + decimal.Parse(line.Total, CultureInfo.InvariantCulture)) .ToString("F2", CultureInfo.InvariantCulture); // 拼接描述和MergedId existingLine.Description += $" | {line.Description}"; existingLine.MergedId += $"|{line.Id}"; } else { // 创建新对象,避免修改原列表元素 var newLine = new Line { Id = line.Id, MergedId = line.Id.ToString(), AccountingTotal = line.AccountingTotal, Description = line.Description, Price = line.Price, Total = line.Total, LineId = line.LineId }; lineDict.Add(line.LineId, newLine); } } var mergedLines = lineDict.Values.ToList();
额外优化建议
- 字段类型优化:将
Price和Total字段直接定义为decimal类型,彻底避免频繁的字符串-数值转换,这是最根本的性能优化 - 字符串拼接规范:大量拼接操作必须用
StringBuilder,避免每次+=产生新的字符串对象 - 避免副作用:原代码直接修改原
lines集合的元素,可能导致其他依赖该集合的逻辑出现异常,推荐创建新对象返回
内容的提问来源于stack exchange,提问作者GThree
相关产品推荐
相关产品推荐

