[英]Select columns dynamically from Datatable C#
我有一个如下所示的Datatable
第 1 列 | 第 2 列 | 第 3 列 | 第 4 栏 |
---|---|---|---|
11 | 10 | 20 | 3 |
35 | 45 | 5 | 10 |
11 | 10 | 30 | 5 |
30 | 13 | 15 | 1 |
数据表有大约 30 列。 示例我提到了 4 列(如上)
var groupbyColumns=list<string>(){"column1","column2"};
var aggregateColumns=List<string>(){"Column3"};
注意:列将根据用户从 UI 中的选择动态更改。
预期结果:
第 1 列 | 第 2 列 | 第 3 列 |
---|---|---|
11 | 10 | 50 |
35 | 45 | 5 |
30 | 13 | 15 |
我必须根据groupbyColumns
列表进行分组,然后根据aggregateColumn
列表对列进行求和。
例如,如果groupbyColumns
包含 2 列并且aggregateColumn
包含 2 列意味着结果必须是 4 列。
有人请帮我实现这一目标吗?
使用IEqualityComparer
for IEnumerable
提供序列相等性,您可以生成可用于GroupBy
的密钥。 我使用 static 方法来简化它的创建过程。
public static class Make {
public static IEqualityComparer<IEnumerable<T>> IESequenceEqual<T>() => new IEnumerableSequenceEqualityComparer<T>();
public static IEqualityComparer<IEnumerable<T>> IESequenceEqual<T>(T _) => new IEnumerableSequenceEqualityComparer<T>();
private class IEnumerableSequenceEqualityComparer<T> : IEqualityComparer<IEnumerable<T>> {
public bool Equals(IEnumerable<T> x, IEnumerable<T> y) =>
Object.ReferenceEquals(x, y) || (x != null && y != null && (x.SequenceEqual(y)));
public int GetHashCode(IEnumerable<T> items) {
// Will not throw an OverflowException
//unchecked {
// return items.Where(e => e != null).Select(e => e.GetHashCode()).Aggregate(17, (a, b) => 23 * a + b);
//}
var hc = new HashCode();
foreach (var item in items)
hc.Add(item);
return hc.ToHashCode();
}
}
}
由于您似乎指定答案应该是DataTable
,因此您需要一个扩展方法来将结果转换为一个。 我使用IDictionary<string,object>
作为中介在动态生成时传递列名和值。
public static class IEnumerableExt {
public static DataTable ToDataTable(this IEnumerable<IDictionary<string, object>> rows) {
var dt = new DataTable();
if (rows.Any()) {
foreach (var kv in rows.First().OrderBy(e => e.Key))
dt.Columns.Add(kv.Key, kv.Value.GetType());
foreach (var r in rows)
dt.Rows.Add(r.Values.Select(v => (object)v).ToArray());
}
return dt;
}
}
现在您只需按groupByColumns
,汇总您的aggregateColumns
并将结果转换为DataTable
。 我使用ValueTuple
来表示要转换为Dictionary
的每个列名、值对。
var groupByColumns = new[] { "Column1", "Column2" }.ToList();
var aggregateColumns = new[] { "Column3" }.ToList();
var ans = src.AsEnumerable()
.GroupBy(r => groupByColumns.Select(c => r[c]), Make.IESequenceEqual<object>())
.Select(rg => groupByColumns.Zip(rg.Key, (c,v) => (c, v))
.Concat(aggregateColumns.Select(c => (c, v:(object)rg.Sum(r => Convert.ToDouble(r[c])))))
.ToDictionary(ck => ck.c, ck => ck.v))
.ToDataTable();
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.