使用LINQ在DataTable中聚合行

时间:2013-12-13 12:27:44

标签: c# linq datatable aggregate-functions

我有DataTable这样的

ProductId CountThisWeek   CountLastWeek
        1          10.0            15.0         
        1          20.0             5.0

        2           5.0            10.0
        2        DBNull            15.0
        2          10.0          DBNull

        3        DBNull            15.0
        3        DBNull            15.0

我需要通过“压缩”(sum by productId)获取一个新的DataTable(或者,如果不是,至少是一个匿名数据结构,如字典),我的初始DataTable,如下所示:

ProductId CountThisWeek   CountLastWeek
        1          30.0            20.0         
        2          15.0            25.0
        3        DBNull            30.0

规则很简单:DBNull + Value = Value,DBNull + DBNull = DBNull

我尝试实现这种聚合,如下所示:

(from row in table.AsEnumerable()
group row by row.Field<int>("ProductId") into g
select g).ToDictionary(
g => g.Key, 
g => new {
   CountThisWeek = g.Sum(r => row.Field<decimal>("CountThisWeek")),
   CountLastWeek = g.Sum(r => row.Field<decimal>("CountLastWeek"))
}

但是这个Sum没有考虑我的DBNull规则...

我无法用可空的十进制做到这一点?

g.Sum(r => r.Field<decimal?>("CountThisWeek")),

所以,也许我需要做一些像

这样的事情
g.Aggregate((summRow, nextRow) => {
                        DataRow dr = summRow.Table.NewRow();
                        decimal? sum = summRow.Field<decimal?>("CountThisWeek");
                        decimal? next = nextRow.Field<decimal?>("CountThisWeek");
                        decimal? result = (!sum.HasValue && !next.HasValue) ? 
                            (decimal?)null : sum ?? 0 + next ?? 0;
                        dr["CountThisWeek"] = result;
                        return dr;
                    }),

这是实现我尝试的最佳方式吗?

我想在集合函数中获取decimal?而不是DataRow ...

2 个答案:

答案 0 :(得分:2)

你可以尝试

(from row in table.AsEnumerable()
group r by r.Field<int>("ProductId") into g
select g).ToDictionary(
g => g.Key, 
g => new {
   CountThisWeek = g.All(r => r.IsNull("CountThisWeek")) ?
                      null : 
                      (decimal?)g.Sum(r => r.Field<decimal>("CountThisWeek")),
   CountLastWeek = g.All(r => r.IsNull("CountLastWeek")) ? 
                       null : 
                       (decimal?)g.Sum(r => r.Field<decimal>("CountLastWeek"))
}

答案 1 :(得分:1)

您可以尝试这样的Aggregate function with Accumulator

g.Aggregate((decimal?)null,(summRow, nextRow) => 
                    nextRow.IsNull("CountThisWeek")?
                        summRow:
                        ((summRow??0) + nextRow.Field<decimal>("CountThisWeek"))
                ),