C# 使用动态列数聚合datatable
我有一个带有动态列集的datatable,希望聚合基于数值的列,并将最后的行保留到新的datatable中 数据表示例:-C# 使用动态列数聚合datatable,c#,dataset,linq-to-dataset,C#,Dataset,Linq To Dataset,我有一个带有动态列集的datatable,希望聚合基于数值的列,并将最后的行保留到新的datatable中 数据表示例:- PartnerName CreditCol DebitCol AmountCol .... P1 10 20 30 P2 1 2 3 P3 3 1 10 P2 1
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查询或任何其他解决方案。以下是一种适合您需求的动态方法:
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];
}
}
结果:
PartnerName CreditCol DebitCol AmountCol
P1 10 20 30
P2 2 102 203
P3 3 1 10
以下是一种适合您需求的动态方法:
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];
}
}
结果:
PartnerName CreditCol DebitCol AmountCol
P1 10 20 30
P2 2 102 203
P3 3 1 10
要聚合的列的类型始终是
int
?您要分组的列始终是一列,还是多列的组合?您尝试过什么吗?主键将基于一列,即PartnerName。对于数字列,它可以是字符串。但是我们必须将其转换为int以进行聚合。您希望它检查每一列是否所有行中的所有值都可以解析为int
?您不能提供要求和的列吗?如果列包含“10.0”
,该怎么办?这显然不是int
,但它可以被解析为decimal
,可以转换为int
,也可以求和为带小数点的十进制值。我尝试执行datarow迭代,但它变得复杂了。我是Linq新手,可能在Linq查询中很容易操作。它总是包含整数数据,不必担心小数。但列集可能会有所不同。如果这是一个昂贵的评估,我们可以跳过解析检查。您希望聚合的列类型始终是int
?您要分组的列始终是一列,还是多列的组合?您尝试过什么吗?主键将基于一列,即PartnerName。对于数字列,它可以是字符串。但是我们必须将其转换为int以进行聚合。您希望它检查每一列是否所有行中的所有值都可以解析为int
?您不能提供要求和的列吗?如果列包含“10.0”
,该怎么办?这显然不是int
,但它可以被解析为decimal
,可以转换为int
,也可以求和为带小数点的十进制值。我尝试执行datarow迭代,但它变得复杂了。我是Linq新手,可能在Linq查询中很容易操作。它总是包含整数数据,不必担心小数。但列集可能会有所不同。如果这是一个昂贵的评估,我们可以跳过解析检查..谢谢soln,让我试着让你保持联系.谢谢soln,让我试着让你保持联系。