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

如何用Linq优化按最大附件大小拆分收件人报表的循环逻辑?

优化报表邮件拆分逻辑:用LINQ替代foreach循环

这段代码的核心功能是将报表与对应接收人关联,当单个收件人对应的报表总大小超过附件上限时,自动拆分出多封邮件。我们可以用LINQ的Aggregate方法替代原有的嵌套foreach循环,让逻辑更连贯,和前面的分组操作衔接更自然。


优化后的完整代码

internal static (List<MailToSend> mailToSends, List<Report> reportsNotUsed) CreateMailsWithReports(
    IList<Report> reports,
    IEnumerable<ReportReceiver> reportReceivers,
    long maxAttachmentSizeInBytes)
{
    // 关联报表与接收人,并按收件人邮箱分组
    var groupedByReceiver = reportReceivers
        .Join(reports,
            receiver => new { receiver.ReportTypeId, receiver.FundId },
            report => new { report.ReportTypeId, report.FundId },
            (receiver, report) => new { Receiver = receiver, Report = report })
        .GroupBy(x => x.Receiver.Email, x => x.Report);

    // 对每个收件人的报表按大小拆分邮件,用Aggregate替代foreach循环
    var mailToSends = groupedByReceiver
        .SelectMany(g => g.Aggregate(
            // 初始状态:空邮件列表 + 未初始化的当前邮件 + 已用字节数0
            (Mails: new List<MailToSend>(), CurrentMail: (MailToSend)null, UsedBytes: 0L),
            (state, report) =>
            {
                if (state.CurrentMail == null)
                {
                    // 首次创建当前收件人的第一封邮件
                    var newMail = new MailToSend { CustomerEmail = g.Key, Reports = new List<Report>() };
                    newMail.Reports.Add(report);
                    state.Mails.Add(newMail);
                    return (state.Mails, newMail, report.SizeInBytes);
                }

                if (state.UsedBytes + report.SizeInBytes <= maxAttachmentSizeInBytes)
                {
                    // 当前邮件仍可添加报表,直接追加
                    state.CurrentMail.Reports.Add(report);
                    return (state.Mails, state.CurrentMail, state.UsedBytes + report.SizeInBytes);
                }
                else
                {
                    // 超过附件上限,新建邮件并添加当前报表
                    var newMail = new MailToSend { CustomerEmail = g.Key, Reports = new List<Report> { report } };
                    state.Mails.Add(newMail);
                    return (state.Mails, newMail, report.SizeInBytes);
                }
            },
            // 最终只提取拆分完成的邮件列表
            state => state.Mails))
        .ToList();

    // 筛选出未匹配到接收人的报表
    var allUsedReports = mailToSends.SelectMany(m => m.Reports);
    var reportsNotUsed = reports.Except(allUsedReports).ToList();

    return (mailToSends, reportsNotUsed);
}

关键逻辑说明

  • 用Aggregate实现状态跟踪:替代原foreach循环中byteUsed和mail两个临时变量,在遍历报表的过程中维护「已生成邮件列表」「当前构建的邮件」「已用字节数」三个状态,完美封装拆分规则。
  • 链式调用衔接分组逻辑:从报表-接收人关联、分组到邮件拆分,全程通过LINQ链式调用完成,无需额外的中间临时集合,逻辑更连贯。
  • 调整未使用报表的计算:从最终拆分后的邮件集合中提取已使用报表,确保结果准确性(原代码基于拆分前的集合计算,存在逻辑偏差)。

内容的提问来源于stack exchange,提问作者Martin Andersen

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 13:10:37