c# - 使用条件选择和汇总 DataTable 行
问题描述
我有这个数据表:
DataTable dt = new DataTable();
dt.Columns.Add("BBG IPC code", typeof(double));
dt.Columns.Add("Issuer Group", typeof(string));
dt.Columns.Add("Seniority", typeof(string));
dt.Columns.Add("Nom Value", typeof(double));
dt.Columns.Add("Mkt Value", typeof(double));
dt.Columns.Add("Rating", typeof(string));
dt.Columns.Add("Sector", typeof(string));
dt.Columns.Add("Analyst", typeof(string));
dt.Rows.Add(new object[] { 117896, "Financiere", "Senior", 101, 20000.76, "BB", "Materials", "BAETZ" });
dt.Rows.Add(new object[] { 117896, "Financiere", "Senior", 356, 300500, "BBB", "Materials", "BAETZ" });
dt.Rows.Add(new object[] { 117896, "Financiere", "Senior", 356, 30000, "BBB", "Energy", "BAETZ" });
dt.Rows.Add(new object[] { 117896, "Financiere", "Covered", 4888, 10000, "BB", "Energy", "BAETZ" });
dt.Rows.Add(new object[] { 117896, "Financiere", "Covered", 645, 50000, "BBB", "Energy", "BAETZ" });
dt.Rows.Add(new object[] { 117897, "Scentre Group", "Senior", 46452, 51066.5, "AA", "Energy", "BAETZ" });
dt.Rows.Add(new object[] { 117898, "Vereniging Achmea", "Senior", 778, 90789.9, "C", "Insurance", "BAETZ" });
dt.Rows.Add(new object[] { 117898, "Vereniging Achmea", "Senior", 7852, 10055.66, "C", "Utilities", "BAETZ" });
对于每对值BBG IPC code
,Seniority
我需要检查列的值是否Rating
相同Sector
,如果相同,则合并这些行并对 and 的值Mkt Value
求和Nom Value
。相反,如果一个或两个不相同,我需要选择具有最高值的行Mkt Value
(如果值相等,只需取 1 行)并丢弃该列中的其他行,但Mkt Value
我Nom Value
仍然需要总和所有的行。
例如:对于BBG IPC code
代码中的数字 117896,有不同的值,Rating
我Sector
需要具有最高值的Mkt Value
行(第二行 300500)并丢弃其他 2 行低Mkt Value
但在丢弃它们之前我需要求和 300500+20000+ 30000 和 356+356+101。结果是 {117896,"Financiere","Senior",813,350500,"BBB", "Materials", "BAETZ"}
我已经尝试过这样的事情,但是有一个错误告诉我我不能在 CopyToDataTable 中放入一个引用字段“Seniority”的字符串值......
DataTable maxIPC_Seniority = dt.AsEnumerable()
.OrderByDescending(x => x.Field<double>("Mkt Value"))
.GroupBy(x => x.Field<double>("IPC"), x => x.Field<string>("Seniority"))
.Select(x => x.FirstOrDefault())
.CopyToDataTable();
并且仍然是对丢弃的行求和的问题。谢谢你的帮助。
解决方案
一个问题是,当您调用 时GroupBy
,您将"IPC"
列设置为Key
选择器,但表中没有"IPC"
列。相反,您应该使用实际的列名"BBG IPC code"
.
下一个问题是您调用的重载GroupBy
将键选择器作为第一个参数,将元素选择器作为第二个参数,因此它只是选择"Seniority"
组中的列。
相反,要按两列作为键进行分组,我们需要为Key
包含列值的属性创建一个新的匿名对象:
var maxIPC_Seniority = dt.AsEnumerable()
.OrderByDescending(row => row.Field<double>("Mkt Value"))
.GroupBy(row =>
new
{
IPC = row.Field<double>("BBG IPC code"),
Seniority = row.Field<string>("Seniority")
})
.Select(group => group.FirstOrDefault())
.CopyToDataTable();
现在,要按照您的意愿组合行,我认为唯一的方法是选择一个object[]
包含新数据的集合,然后将它们添加到结果表中,因为我们不能只创建一个DataRow
没有a DataTable
,所以我的回答做了三件事:
DataTable
使用所需的列创建一个新的- 从原始表中选择合并的数据作为
IEnumerable<object[]>
- 将每个
object[]
作为 a添加DataRow
到DataTable
步骤 1
例如:
// Create a new DataTable with the same columns as `dt`
DataTable maxIpcSeniority = dt.Clone();
// Group our set of original data, do the merging of rows as necessary
// and then return the row data as a list of object[]
var maxIpcSeniorityRowData = dt.AsEnumerable()
.OrderByDescending(row => row.Field<double>("Mkt Value"))
.GroupBy(row =>
new
{
IPC = row.Field<double>("BBG IPC code"),
Seniority = row.Field<string>("Seniority")
})
.Select(group =>
{
// Since the data is ordered by MktValue already, we can just grab
// the first one to use for filling in the non-merged fields
var firstRow = group.First();
return new object[]
{
group.Key.IPC,
firstRow.Field<string>("Issuer Group"),
group.Key.Seniority,
group.Sum(row => row.Field<double>("Nom Value")),
group.Sum(row => row.Field<double>("Mkt Value")),
firstRow.Field<string>("Rating"),
firstRow.Field<string>("Sector"),
firstRow.Field<string>("Analyst")
};
})
.ToList();
// Add each set of rowData to our new table
foreach (var rowData in maxIpcSeniorityRowData)
{
maxIpcSeniority.Rows.Add(rowData);
}
如果由于某种原因不能使用花括号,则可以使用Tuple
(甚至创建单独的类)来存储GroupBy
字段而不是匿名类型。这样,您可以通过构造函数添加值,而不是在花括号中初始化属性。(请注意,如果您确实创建了一个类来执行此操作,则需要覆盖Equals
并且GetHashCode
分组才能正常工作)。
这是一个使用 a 的示例Tuple<double, string>
:
var maxIpcSeniorityRowData = dt.AsEnumerable()
.OrderByDescending(row => row.Field<double>("Mkt Value"))
.GroupBy(row => new Tuple<double, string>(
row.Field<double>("BBG IPC code"),
row.Field<string>("Seniority")))
.Select(group =>
{
var firstRow = group.First();
return new object[]
{
group.Key.Item1,
firstRow.Field<string>("Issuer Group"),
group.Key.Item2,
group.Sum(row => row.Field<double>("Nom Value")),
group.Sum(row => row.Field<double>("Mkt Value")),
firstRow.Field<string>("Rating"),
firstRow.Field<string>("Sector"),
firstRow.Field<string>("Analyst")
};
})
.ToList();
推荐阅读
- java - 如何修复错误原因:java.lang.module.InvalidModuleDescriptorException,找不到JsonFactory,如何添加?
- android - 我有一个 custom_list_view 的问题。错误就在那一行 setContentView(R.layout.activity_main);
- java - 当我在 sts 中创建 web 启动项目时,它在 pom 和 java 文件中显示错误
- c++11 - 想要定义具有相同前缀的宏列表
- php - 无法使用 PHP 按相同键对 json 对象进行排序
- ios - 我的 .ipa 中的“符号文件太多”但 dSYM 文件丢失
- google-apps-script - 我正在制作一个脚本来更新谷歌表格中的最后更新列,但我有各种表格用于添加条目
- node.js - 在mongodb中过滤2个数组后如何获取文档?
- excel - Excel VBA - Application.Visible = False 不工作
- sql - 如何将其转换为 laravel