【问题标题】:Aggregate datatable with dynamic number of columns使用动态列数聚合数据表
【发布时间】:2014-06-25 13:45:34
【问题描述】:

我有一个包含动态列集的数据表,并希望聚合基于数字的列并将最终行保留到新数据表中。

数据表示例:-

PartnerName   CreditCol  DebitCol  AmountCol ....
P1              10       20        30 
P2              1        2         3 
P3              3        1         10
P2              1        100       200

所需的输出应该是:-

PartnerName   CreditCol  DebitCol  AmountCol ....
P1              10       20        30 
P2              2        102       203 
P3              3        1         10

这里的主要内容是列集,将是动态的。有时,可能有两列,有时可能是 20 列。请建议 linq 查询或任何其他解决方案。

【问题讨论】:

  • 要聚合的列的类型是否总是int?您要分组的列总是一列还是可以是多列的组合?你有没有尝试过?
  • 主键将基于一列,即 PartnerName。对于数字列,它可以是字符串。但我们必须将其转换为 int 以进行聚合。
  • 如果所有行中的所有值都可以解析为int,您希望它检查每一列吗?你不能提供你想求和的列吗?如果列包含"10.0" 怎么办?这显然不是int,但可以解析为decimal,后者可以转换为int,或求和为带小数位的十进制值。
  • 我尝试执行数据行迭代,但它变得越来越复杂。我是 Linq 新手,可能很容易在 linq 查询中操作。
  • 它将始终包含整数数据,无需担心小数。但是列集可能会有所不同。如果它是一个昂贵的评估,我们可以跳过解析检查..

标签: c# dataset linq-to-dataset


【解决方案1】:

这是一种动态方法,应该可以满足您的要求:

var rows = table.AsEnumerable();
var columns = table.Columns.Cast<DataColumn>();
int i;  // used to check if a string column can be parsed to int
string columnToGroup = "partnername";
DataColumn colToGroup = columns.First(c => c.ColumnName.Equals(columnToGroup, StringComparison.OrdinalIgnoreCase));
var colsToSum = columns
     .Where(c => c != colToGroup &&
         (c.DataType == typeof(int) ||
         (c.DataType == typeof(string)
         && rows.All(r => int.TryParse(r.Field<string>(c), out i)))));
var columnsToSum = new HashSet<DataColumn>(colsToSum);

DataTable tblSum = table.Clone(); // empty table, same schema
foreach (var group in rows.GroupBy(r => r[colToGroup]))
{
    DataRow row = tblSum.Rows.Add();
    foreach(var col in columns)
    {
        if (columnsToSum.Contains(col))
        {
            int sum;
            if (col.DataType == typeof(int))
                sum = group.Sum(r => r.Field<int>(col));
            else
                sum = group.Sum(r => int.Parse(r.Field<string>(col)));
            row.SetField(col.ColumnName, sum);
        }
        else
            row[col.ColumnName] = group.First()[col];
    }
}

在此处使用您的示例数据进行测试:

var table = new System.Data.DataTable();
table.Columns.Add("PartnerName", typeof(string));
table.Columns.Add("CreditCol", typeof(int));
table.Columns.Add("DebitCol", typeof(string));
table.Columns.Add("AmountCol", typeof(int));
table.Rows.Add("P1", 10, "20", 30);
table.Rows.Add("P2", 1, "2", 3);
table.Rows.Add("P3", 3, "1", 10);
table.Rows.Add("P2", 1, "100", 200);

结果:

PartnerName   CreditCol    DebitCol    AmountCol
P1            10             20         30
P2            2              102        203
P3            3              1          10

【讨论】:

  • 感谢您的解决,让我试着让您保持最新状态。
猜你喜欢
  • 2017-06-21
  • 2015-03-24
  • 2018-07-11
  • 1970-01-01
  • 2020-01-19
  • 1970-01-01
  • 2020-02-14
  • 1970-01-01
  • 2018-10-03
相关资源
最近更新 更多