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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 21:45:03