C#用DataTable实现Group by数据统计

本文介绍三种使用DataTable进行分组统计的方法:通过双层循环、利用Compute方法及LINQ to DataTable结合GroupBy。这些方法适用于不同场景的数据处理需求。

1、用两层循环计算,前提条件是数据已经按分组的列排好序的。

DataTable dt = new DataTable();
dt.Columns.AddRange(new DataColumn[] { new DataColumn("name"typeof(string)),
                                        new DataColumn("sex"typeof(string)),
                                        new DataColumn("score"typeof(int)) });
dt.Rows.Add(new object[] { "张三","男",1 });
dt.Rows.Add(new object[] { "张三","男",4 });
dt.Rows.Add(new object[] { "李四","男",100 });
dt.Rows.Add(new object[] { "李四","女",90 });
dt.Rows.Add(new object[] { "王五","女",77 });
DataTable dtResult = dt.Clone();
for (int i = 0; i < dt.Rows.Count; )
{
    DataRow dr = dtResult.NewRow();
    string name = dt.Rows[i]["name"].ToString();
    string sex = dt.Rows[i]["sex"].ToString();
    dr["name"] = name;
    dr["sex"] = sex;
    int score = 0;
    //内层也是循环同一个表,当遇到不同的name时跳出内层循环
    for (; i < dt.Rows.Count; )
    {
        if (name == dt.Rows[i]["name"].ToString()&&name == dt.Rows[i]["sex"].ToString())
        {
            score += Convert.ToInt32(dt.Rows[i]["score"]);
            dr["score"] = score;
            i++;
        }
        else
        {
            break;
        }
    }
    dtResult.Rows.Add(dr);

}

dtResult中的数据即是最终结果。 

2、 借助DataTable的Compute方法,DataTable中数据不用事先排好序。

DataTable dt = new DataTable();
dt.Columns.AddRange(new DataColumn[] { new DataColumn("name"typeof(string)),
                                         new DataColumn("sex"typeof(string)),
                                         new DataColumn("score"typeof(int)) });
dt.Rows.Add(new object[] { "张三","男",1 });
dt.Rows.Add(new object[] { "张三","男",4 });
dt.Rows.Add(new object[] { "李四","男",100 });
dt.Rows.Add(new object[] { "李四","女",90 });
dt.Rows.Add(new object[] { "王五","女",77 });
DataTable dtResult = dt.Clone();
DataTable dtName = dt.DefaultView.ToTable(true"name","sex");
for (int i = 0; i < dtName.Rows.Count; i++)
{
    DataRow[] rows = dt.Select("name='" + dtName.Rows[i][0] + "' and sex='" + dtName.Rows[i][1] + "'");
    //temp用来存储筛选出来的数据
    DataTable temp = dtResult.Clone();
    foreach (DataRow row in rows)
    {
        temp.Rows.Add(row.ItemArray);
    }

    DataRow dr = dtResult.NewRow();
    dr[0] = dtName.Rows[i][0].ToString();
    dr[1] = temp.Compute("sum(score)""");
    dtResult.Rows.Add(dr);

3、使用linq to DataTable group by实现

var query = from t in dt.AsEnumerable()
            group t by new { t1 = t.Field<string>("name"), t2 = t.Field<string>("sex") } into m
            select new
            {
                name = m.Key.t1,
                sex = m.Key.t2,
                score = m.Sum(n => n.Field<decimal>("score"))
            };
if (query.ToList().Count > 0)
{
    query.ToList().ForEach(q =>
    {
        Console.WriteLine(q.name + "," + q.sex + "," + q.score);
    });
} 

<think> 首先,用户的问题是:使用C#DataTable的某几列数据进行Group By操作并汇总数据的方法。用户参考了几个引用:[^1], [^2], [^3]。我需要基于这些引用和用户的问题来回答。 回顾引用内容: - [^1]: 解释了DataSetDataTable的概念,DataSet类似一个小数据库,包含DataTable等。 - [^2]: 展示了使用LINQ对DataTable进行Group By并计数的方法,包括分组和拼接字符串。 - [^3]: 提到给报表单元格赋值,涉及从数据库取值和计算。 用户的问题核心是实现C#中对DataTable的列进行Group By汇总数据。我需要提供一个清晰、结构化的回答。 系统指令: - 所有行内数学表达式用$...$,但这里可能不涉及数学表达式。 - 独立公式用$$...$$,但这里可能不适用。 - LaTeX语法正确,但代码块使用markdown高亮。 - 使用中文回答。 - 生成相关问题。 - 回答中引用的段落末尾添加引用标识如[^1]。 回答结构: 1. **介绍问题**:解释Group ByDataTable中的作用和数据汇总。 2. **实现方法**:基于[^2]中的示例,提供一个使用LINQ的分步实现。 3. **代码示例**:给出一个完整的C#代码示例。 4. **解释代码**:简要解释代码的关键部分。 5. **总结**。 6. **生成相关问题**。 关键点: - 用户要Group By"某几列",意思是多列分组。 - 汇总数据可能包括计数、求和、平均等。 - [^2]中使用了LINQ:`group t by new { t1 = t.Field<string>("mineid") } into m select new { MineID = m.Key.t1, count = m.Count() }`。这是一个示例分组一个列并计数。 我需要扩展这个来支持多列分组和不同类型的汇总。 步骤: 1. **导入必要的命名空间**:比如System.Linq。 2. **获取DataTable的行集合**:使用`AsEnumerable()`。 3. **定义分组键**:使用匿名类型指定多个列。 4. **分组并汇总**:使用`group by`和`select new`来计算汇总值。 5. **可选:将结果转换回DataTable**。 代码示例: 假设DataTable有列如"Category", "SubCategory", "Sales"。我们要按"Category"和"SubCategory"分组,并计算总销售额。 ```csharp using System; using System.Data; using System.Linq; public class DataTableGroupByExample { public static void Main() { // 创建一个示例DataTable DataTable salesData = new DataTable(); salesData.Columns.Add("Category", typeof(string)); salesData.Columns.Add("SubCategory", typeof(string)); salesData.Columns.Add("Sales", typeof(decimal)); // 添加一些数据行 salesData.Rows.Add("Electronics", "TV", 1000); salesData.Rows.Add("Electronics", "TV", 1200); salesData.Rows.Add("Electronics", "Phone", 800); salesData.Rows.Add("Clothing", "Shirt", 50); salesData.Rows.Add("Clothing", "Shirt", 60); salesData.Rows.Add("Clothing", "Pants", 80); // 使用LINQ进行Group By操作 var groupedData = from row in salesData.AsEnumerable() group row by new { Category = row.Field<string>("Category"), SubCategory = row.Field<string>("SubCategory") } into g select new { g.Key.Category, g.Key.SubCategory, TotalSales = g.Sum(r => r.Field<decimal>("Sales")), // 汇总销售额 Count = g.Count() // 可选:计数 }; // 输出结果或转换回DataTable Console.WriteLine("Group By结果:"); foreach (var item in groupedData) { Console.WriteLine($"Category: {item.Category}, SubCategory: {item.SubCategory}, Total Sales: {item.TotalSales}, Count: {item.Count}"); } // 如果需要将结果放回DataTable DataTable resultTable = new DataTable(); resultTable.Columns.Add("Category", typeof(string)); resultTable.Columns.Add("SubCategory", typeof(string)); resultTable.Columns.Add("TotalSales", typeof(decimal)); resultTable.Columns.Add("Count", typeof(int)); foreach (var item in groupedData) { resultTable.Rows.Add(item.Category, item.SubCategory, item.TotalSales, item.Count); } } } ``` 解释: - `salesData.AsEnumerable()`:允许使用LINQ操作。 - `group row by new { ... } into g`:按指定列分组。 - `select new { ... }`:创建新对象,包括分组键和汇总值如TotalSales(使用`Sum`)和Count(使用`Count`)。 - 最后,将结果转换回DataTable是可选的。 需要考虑用户引用: - [^1] 提到了DataSetDataTable,可以引用以强调上下文。 - [^2] 直接展示了类似代码,可以基于此扩展。 - [^3] 涉及计算,与汇总相关。 在回答中,自然地添加引用标识: - 例如,当提到DataTable时,可以引用[^1]:"DataSet是一个数据集合,保存读取到的数据,类似一个独立的小数据库[^1]。" - 当讨论Group By实现时,引用[^2]。 生成相关问题:在最后添加几个相关问题。 完整回答结构: 1. 介绍Group By概念和在DataTable中的必要性。 2. 提供实现方法的步骤。 3. 展示代码示例。 4. 解释关键点。 5. 总结。 6. 相关问题。 </think> ### C#DataTable 某几列数据进行 Group By 汇总数据的实现方法 在 C# 中,对 `DataTable` 的指定列执行 Group By 操作并汇总数据(如计数、求和、平均值等),可以通过 LINQ to DataSet 实现。这种方法高效且代码简洁。以下是逐步说明和完整示例: #### 1. **核心实现步骤** - **步骤 1:导入必要命名空间** 使用 `System.Linq` 和 `System.Data` 以支持 LINQ 操作。 - **步骤 2:定义分组键** 使用匿名类型 `new { }` 指定需要分组的列名(支持多列)。 - **步骤 3:执行 Group By 操作** 通过 `AsEnumerable()` 将 `DataTable` 转换为可 LINQ 查询的集合,然后使用 `group ... by ... into g` 分组。 - **步骤 4:计算汇总值** 在 `select` 子句中使用聚合函数如 `Count()`(计数)、`Sum()`(求和)或 `Average()`(平均值)。 - **步骤 5:处理结果** 可直接遍历匿名类型结果,或将其转换回新的 `DataTable`。 #### 2. **完整代码示例** ```csharp using System; using System.Data; using System.Linq; public class DataTableGroupByExample { public static void Main() { // 创建示例 DataTable(模拟数据源) DataTable salesDt = new DataTable("SalesData"); salesDt.Columns.Add("Region", typeof(string)); // 分组列1 salesDt.Columns.Add("Product", typeof(string)); // 分组列2 salesDt.Columns.Add("Sales", typeof(decimal)); // 待汇总的数值列 salesDt.Columns.Add("Quantity", typeof(int)); // 待汇总的数值列 // 添加示例数据行 salesDt.Rows.Add("North", "Apple", 1500, 30); salesDt.Rows.Add("North", "Apple", 2000, 40); salesDt.Rows.Add("South", "Banana", 800, 20); salesDt.Rows.Add("South", "Banana", 1200, 25); salesDt.Rows.Add("North", "Banana", 900, 15); // 步骤:按 Region 和 Product 分组,计算总销售额和总数量 var groupedQuery = from row in salesDt.AsEnumerable() group row by new { Region = row.Field<string>("Region"), Product = row.Field<string>("Product") } into g // g 代表分组后的集合 select new { Region = g.Key.Region, Product = g.Key.Product, TotalSales = g.Sum(r => r.Field<decimal>("Sales")), // 汇总销售额 TotalQuantity = g.Sum(r => r.Field<int>("Quantity")), // 汇总数量 EntryCount = g.Count() // 分组条目计数 }; // 输出结果 Console.WriteLine("Group By 结果:"); foreach (var item in groupedQuery) { Console.WriteLine( $"Region: {item.Region}, Product: {item.Product}, " + $"总销售额: {item.TotalSales}, 总数量: {item.TotalQuantity}, 条目数: {item.EntryCount}"); } // 可选:将结果转换回 DataTable(适用于数据绑定或导出) DataTable resultDt = new DataTable(); resultDt.Columns.Add("Region", typeof(string)); resultDt.Columns.Add("Product", typeof(string)); resultDt.Columns.Add("TotalSales", typeof(decimal)); resultDt.Columns.Add("TotalQuantity", typeof(int)); resultDt.Columns.Add("EntryCount", typeof(int)); foreach (var item in groupedQuery) { resultDt.Rows.Add(item.Region, item.Product, item.TotalSales, item.TotalQuantity, item.EntryCount); } } } ``` #### 3. **代码关键点解释** - **分组键定义**: `group row by new { Region = row.Field<string>("Region"), Product = row.Field<string>("Product") }` 指定按多列分组。若需单列,移除多余属性即可。 - **聚合函数**: - `g.Sum()`:计算数值列的总和(如销售额)。 - `g.Count()`:统计分组内的行数。 - 其他函数如 `Average()`(平均值)、`Min()`(最小值)也可直接使用。 - **类型安全**: 使用 `row.Field<T>("列名")` 确保数据类型正确,避免运行时错误[^1]。 - **性能优化**: LINQ 查询在内存中执行,适用于中小型数据集。大型数据集建议在数据库层汇总[^3]。 #### 4. **注意事项** - **引用依赖**:确保项目已引用 `System.Core`(含 LINQ)和 `System.Data.DataSetExtensions`。 - **空值处理**:若数据列可能包含 `null`,使用 `Field<T?>("列名")` 可空类型。 - **动态列支持**:若列名在运行时确定,可通过字符串变量构建匿名类型(需反射或动态 LINQ)。 此方法高效灵活,是处理 `DataTable` 分组汇总的标准实践[^2]。通过组合不同聚合函数,可轻松扩展为复杂业务逻辑(如报表统计)[^3]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值