【问题标题】:Aggregate rows in a DataTable using LINQ使用 LINQ 聚合数据表中的行
【发布时间】:2013-12-13 12:27:44
【问题描述】:

我有一个这样的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

我需要通过“压缩”(按 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...

【问题讨论】:

  • 你试试g.Sum(r =&gt; r.Field&lt;decimal&gt;("CountThisWeek")??0)
  • 不,DbNull+DbNull 应该是“null”,而不是“0”

标签: c# linq datatable aggregate-functions


【解决方案1】:

你可以试试

(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"))
}

【讨论】:

  • 你正好有 10,000 个代表,我受不了,投票吧。
【解决方案2】:

你可以试试Aggregate function with Accumulator这样

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

【讨论】:

  • 据我了解,聚合的“性能”比总和更好。 ... 来自&lt;decimal?&gt; => &lt;decimal&gt; 的良好修复...顺便说一下,在我的情况下,它在“十进制”的情况下返回 InvalidCastException,在“双”的情况下返回正确的值...
  • 可能是因为您的字段是双精度而不是十进制?
  • @serhio,关于性能,它取决于将在其上执行函数的数据集,Aggregate 在所有情况下都会对所有集合循环一次,在示例中@BobVale 可能最小操作计数是集合.lenght 如果全部为空,max - collection.lenght*2
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-03
  • 1970-01-01
  • 2018-11-16
相关资源
最近更新 更多