完全披露,我几乎是一个彻头彻尾的菜鸟。我可以基于我应该如何处理这个问题。
我有一个 3 列的DataTable
类,idate,数量
每个 ID 有多个日期,每个日期有多个金额。我需要做的是将每个 id 每天的金额相加,而不是:
- ID,日期,金额
- 00045,2011/02/13,11.50
- 00045,2011/02/14,11.00
- 00045,2011/02/14,12.00
- 00045,2011/02/15,10.00
- 00045,2011/02/15,5.00
- 00045,2011/02/15,12.00
- 00054,2011/02/13,8.00
- 00054,2011/02/13,9.00
我会:
- id,日期,金额总和
- 00045,2011/02/13,11.50
- 00045,2011/02/14,23.00
- 00045,2011/02/15,27.00
- 00054,2011/02/13,17.00
private void excelDaily_Copy_Into(DataTable copyFrom, DataTable copyTo)
{
var results = from row in copyFrom.AsEnumerable()
group row by new
{
oid = row["oid"],
idate = row["idate"]
} into n
select new
{
///unsure what to do
}
};
我已经尝试了十几种不同的方法来做到这一点,我总是碰壁,我不知道如何进步。我一直在堆栈溢出和 msdn 上,到目前为止没有什么真正帮助我。
提前谢谢你!
你可以试试这个:
var results = from row in copyFrom.AsEnumerable()
group row by new
{
oid = row.Field<int>("oid"),// Or string, depending what is the real type of your column
idate = row.Field<DateTime>("idate")
} into g
select new
{
g.Key.oid,
g.Key.idate,
SumOfAmounts=g.Sum(e=>e.Field<decimal>("amount"));
};
我建议使用 Field 扩展方法,该方法提供对指定行中每个列值的强类型访问。
虽然你没有指定它,但显然 copyFrom 是实现 IEnumerable 的类 DataTable 中的一个对象。
根据MSDN System.Data.DataTable,该类没有实现它。如果使用该类,则需要属性 Rows,该属性返回实现 IEnumerable 的行集合:
IEnumerable<DataRow> rows = copyFrom.Rows.Cast<DataRow>()
但是,如果您使用不同的 DataTable 类,则可能会执行类似操作以将其强制转换为 DataRow 序列。
类 System.Data.DataRow 的对象具有用于访问行中列的项属性。在您的情况下,列名是 oid、idate 和 amount。
要将副本从转换为要对其进行处理的项目序列,请执行以下操作:
var itemsToProcess = copyFrom.Rows.Cast<DataRow>()
.Select(row => new
{
Oid = row["oid"],
Date = (DateTime)row["idate"],
Amount = (decimal)row["amount"],
});
我不确定,但我假设列 idate 包含日期,列金额包含一些值。如果您的列包含其他类型,请随意使用其他类型。
如果列包含字符串,请使用 Parse 将它们转换为正确的项:
var itemsToProcess = copyFrom.Rows.Cast<DataRow>()
.Select(row => new
{
Id = (string)row["oid"],
Date = DateTime.Parse( (string) row["idate"]),
Amount = Decimal.Parse (string) row["amount"]),
});
如果您不熟悉 lambda 表达式。阅读以下内容对我有很大帮助:
itemsToProcess 是项的集合,取自 数据行,我们从此集合中的每一行创建了一个新的 具有三个属性的对象:Id = ...;数据 = ...;金额 = ...
看
- 用于铸造和选择的标准 Linq 配置的说明
- 匿名类型
现在我们有一个序列,我们可以在其中比较日期并对金额求和。
您想要的是将此序列中的所有项目分组到具有相同 ID 和日期的组中。因此,您需要一个
Id = 00045 且日期 = 02/13/2011 的组,以及一个 Id = 00045 且日期 = ,02/14/2011 的组。为此,您可以使用Enumerable.GroupBy。作为选择器(= 一个组中的所有项目共有),您使用 ID 和日期的组合:
var groups = itemsToProcess.GroupBy(item => new
{Id = item.Id, Data = item.Data} );
现在你有组了。
- 每个组都有一个属性 Key,其类型具有两个属性:Id 和 Data。
- 每个组都是 itemsToProcess 集合中的一系列项(因此它是具有 Id/数据/值属性的"itemToprocess")
- 一个组中的所有项目都具有相同的 ID 和相同的数据。
因此,您所要做的就是对每个组中序列中的所有元素求和。
var resultSequence = groups.Select(groupItem => new
{
Id = groupItem.Key.Id
Date = groupItem.Key.Date,
Sum = groupItem.Sum(itemToProcess => itemToProcess.Value,
}
所以把它们放在一个语句中:
var resultSequence = copyFrom.Rows.Cast<DataRow>()
.Select(row => new
{
Id = (string)row["oid"],
Date = DateTime.Parse( (string) row["idate"]),
Amount = Decimal.Parse (string) row["amount"]),
})
.GroupBy (itemToProcess => new
{
Id = item.Id,
Data = item.Data
});
.Select(groupItem => new
{
Id = groupItem.Key.Id
Date = groupItem.Key.Date,
Sum = groupItem.Sum(itemToProcess => itemToProcess.Value,
});