c# - 从 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
。我使用静态方法来简化创建它的过程。
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();
}
}
}
由于您似乎指定答案应该是 a 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();
推荐阅读
- mysql - Nach Umzug auf neuen 服务器身份验证失败
- wordpress - woocommerce 为未登录用户隐藏字段
- angular - 使用自定义事件触发点击事件监听器
- android - cordova 安装 Android 目标:未安装(使用 sdkmanager)
- generics - Kotlin 中的使用站点差异
- android - 如何修复此错误 Android Studio gradle 同步错误
- sql - 如果列具有多个不同的值,则 SQL 过滤器查询
- command-line - 用于删除 Windows Defender 历史记录的 PowerShell cmdlet
- node.js - Node js - http请求在循环中无法按预期工作
- javascript - AngularJS 是否可以直接使用通过 html 范围注入的服务?