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

如何优化统计戒指尺寸数量的LINQ查询,使其更简洁复用性更高?

原有代码的核心问题

  • 重复遍历戒指尺寸集合近30次,数据量大时性能损耗极高
  • 所有尺寸值和赋值逻辑全部硬编码,后续新增/删除尺寸需要修改大量代码,维护成本很高
  • 缺少空值兼容处理,selector返回null时可能出现匹配异常

优化实现方案

我们可以通过LINQ的GroupBy一次性统计所有尺寸的数量,仅遍历集合1次,根据是否能修改Dto结构分为两种场景:

场景1:不修改现有RingSizeLettersDto定义

如果Dto已有外部依赖、接口契约固定无法调整结构,用单次分组统计结果后统一赋值即可:

private async Task<RingSizeLettersDto> CountOfLettersByRingFingerAsync(Func<RingSize, string> selector)
{
    var ringSizes = await _ringSizeRepository.Get();
    // 一次性分组统计所有尺寸的数量,仅遍历集合1次
    var countDict = ringSizes
        .GroupBy(x => selector(x)?.Trim() ?? "N/A")
        .ToDictionary(g => g.Key, g => g.Count());

    var ringSizeLetters = new RingSizeLettersDto();
    ringSizeLetters.G = countDict.TryGetValue("G", out var gCnt) ? gCnt : 0;
    ringSizeLetters.H = countDict.TryGetValue("H", out var hCnt) ? hCnt : 0;
    ringSizeLetters.I = countDict.TryGetValue("I", out var iCnt) ? iCnt : 0;
    ringSizeLetters.J = countDict.TryGetValue("J", out var jCnt) ? jCnt : 0;
    ringSizeLetters.K = countDict.TryGetValue("K", out var kCnt) ? kCnt : 0;
    ringSizeLetters.L = countDict.TryGetValue("L", out var lCnt) ? lCnt : 0;
    ringSizeLetters.M = countDict.TryGetValue("M", out var mCnt) ? mCnt : 0;
    ringSizeLetters.N = countDict.TryGetValue("N", out var nCnt) ? nCnt : 0;
    ringSizeLetters.O = countDict.TryGetValue("O", out var oCnt) ? oCnt : 0;
    ringSizeLetters.P = countDict.TryGetValue("P", out var pCnt) ? pCnt : 0;
    ringSizeLetters.Q = countDict.TryGetValue("Q", out var qCnt) ? qCnt : 0;
    ringSizeLetters.R = countDict.TryGetValue("R", out var rCnt) ? rCnt : 0;
    ringSizeLetters.S = countDict.TryGetValue("S", out var sCnt) ? sCnt : 0;
    ringSizeLetters.T = countDict.TryGetValue("T", out var tCnt) ? tCnt : 0;
    ringSizeLetters.U = countDict.TryGetValue("U", out var uCnt) ? uCnt : 0;
    ringSizeLetters.V = countDict.TryGetValue("V", out var vCnt) ? vCnt : 0;
    ringSizeLetters.W = countDict.TryGetValue("W", out var wCnt) ? wCnt : 0;
    ringSizeLetters.X = countDict.TryGetValue("X", out var xCnt) ? xCnt : 0;
    ringSizeLetters.Y = countDict.TryGetValue("Y", out var yCnt) ? yCnt : 0;
    ringSizeLetters.Z = countDict.TryGetValue("Z", out var zCnt) ? zCnt : 0;
    ringSizeLetters.Z1 = countDict.TryGetValue("Z1", out var z1Cnt) ? z1Cnt : 0;
    ringSizeLetters.Z2 = countDict.TryGetValue("Z2", out var z2Cnt) ? z2Cnt : 0;
    ringSizeLetters.Z3 = countDict.TryGetValue("Z3", out var z3Cnt) ? z3Cnt : 0;
    ringSizeLetters.Z4 = countDict.TryGetValue("Z4", out var z4Cnt) ? z4Cnt : 0;
    ringSizeLetters.Z5 = countDict.TryGetValue("Z5", out var z5Cnt) ? z5Cnt : 0;
    ringSizeLetters.Z6 = countDict.TryGetValue("Z6", out var z6Cnt) ? z6Cnt : 0;
    ringSizeLetters.NA = countDict.TryGetValue("N/A", out var naCnt) ? naCnt : 0;

    return ringSizeLetters;
}

如果想要进一步减少重复代码,可以预先建立尺寸和Dto属性的映射关系,通过反射自动赋值,后续新增尺寸仅需要更新映射列表即可:

// 尺寸与Dto属性的映射全局仅需要初始化一次
private static readonly Dictionary<string, PropertyInfo> _sizePropertyMap = typeof(RingSizeLettersDto)
    .GetProperties()
    .ToDictionary(
        p => p.Name == "NA" ? "N/A" : p.Name, 
        p => p
    );

private async Task<RingSizeLettersDto> CountOfLettersByRingFingerAsync(Func<RingSize, string> selector)
{
    var ringSizes = await _ringSizeRepository.Get();
    var countDict = ringSizes
        .GroupBy(x => selector(x)?.Trim() ?? "N/A")
        .ToDictionary(g => g.Key, g => g.Count());

    var ringSizeLetters = new RingSizeLettersDto();
    foreach (var (sizeKey, property) in _sizePropertyMap)
    {
        property.SetValue(ringSizeLetters, countDict.TryGetValue(sizeKey, out var cnt) ? cnt : 0);
    }
    return ringSizeLetters;
}

场景2:可调整RingSizeLettersDto定义

这是最优方案,直接把计数逻辑改成字典存储,后续新增尺寸完全不需要修改业务代码:

// 调整后的Dto定义,原有快捷访问属性可保留兼容旧逻辑
public class RingSizeLettersDto
{
    public Dictionary<string, int> SizeCounts { get; set; } = new();
    public int G => SizeCounts.TryGetValue("G", out var cnt) ? cnt : 0;
    public int H => SizeCounts.TryGetValue("H", out var cnt) ? cnt : 0;
    // 其他原有尺寸属性同理保留即可
}

// 优化后的业务代码
private async Task<RingSizeLettersDto> CountOfLettersByRingFingerAsync(Func<RingSize, string> selector)
{
    var ringSizes = await _ringSizeRepository.Get();
    var countDict = ringSizes
        .GroupBy(x => selector(x)?.Trim() ?? "N/A")
        .ToDictionary(g => g.Key, g => g.Count());
    
    return new RingSizeLettersDto
    {
        SizeCounts = countDict
    };
}

额外性能优化建议

如果你使用的是EF/EF Core这类ORM,_ringSizeRepository.Get()返回的是IQueryable<RingSize>,可以把参数从Func<RingSize, string>改成Expression<Func<RingSize, string>>,这样分组操作会直接在数据库层面执行,不需要拉取全量数据到内存计算,性能提升非常明显。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 23:57:02