DataTable 分组聚合与按 Key 查找

场景一:多层分组转 Dictionary

DataTable 按多个字段分组,再按子字段二次分组并求和,最终得到一个两层嵌套的字典结构。

var list = dt2.AsEnumerable()
    .GroupBy(p => new 
    { 
        ywrq = p.Field<string>("ywrq"), 
        xmmc = p.Field<string>("xmmc"), 
        ryxzmc = p.Field<string>("ryxzmc") 
    })
    .ToDictionary(
        p => p.Key, 
        p => p.GroupBy(x => new { sffsmc = x.Field<string>("sffsmc") })
              .ToDictionary(
                  x => x.Key, 
                  x => x.Sum(r => r.Field<decimal>("je"))
              )
    );Code language: JavaScript (javascript)

结果结构:

Dictionary<
  外层Key (ywrq, xmmc, ryxzmc),
  Dictionary<
    内层Key (sffsmc),
    decimal (je 求和)
  >
>

访问方式:

// 取某个分组下某个收费方式的金额
var je = list[outerKey][innerKey];Code language: PHP (php)

场景二:按分组 Key 在 DataTable 中查找匹配行

分组后拿到 Key,需要回原 DataTable 中找到匹配的原始行。

DataRow row = dt.AsEnumerable()
    .Where(m => m.Field<string>("ywrq") == item.Key.ywrq 
             && m.Field<string>("xmmc") == item.Key.xmmc 
             && m.Field<string>("ryxzmc") == item.Key.ryxzmc)
    .FirstOrDefault();Code language: JavaScript (javascript)

说明:

写法说明
AsEnumerable()DataTable 转为 IEnumerable<DataRow>
Field<T>("列名")类型安全地读取列值,支持可空类型
FirstOrDefault()返回第一条匹配行,无匹配返回 null
匿名对象 Key 对比匿名对象按属性值逐个比较,所有字段相等则视为同一 Key

关键要点

要点说明
Field<T>读取 DataRow 列值,比 row["列名"] 更安全,支持可空类型
匿名对象作 Key自动实现 EqualsGetHashCode,适合分组和查找
多层 ToDictionary外层分组 → 内层子分组 → 聚合值
FirstOrDefault查找不到返回 null,需判空再使用
性能Where 逐行扫描,数据量大时考虑先 ToDictionary 建索引

建索引优化(数据量大时):

// 先建索引,避免多次扫描
var index = dt.AsEnumerable()
    .GroupBy(m => new 
    { 
        ywrq = m.Field<string>("ywrq"), 
        xmmc = m.Field<string>("xmmc"), 
        ryxzmc = m.Field<string>("ryxzmc") 
    })
    .ToDictionary(g => g.Key, g => g.First());

// 直接按 Key 取
DataRow row = index[item.Key];Code language: JavaScript (javascript)

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注