我有一个巨大的dataTable(大约500k-600k行)。我想根据某些特定列计算行数。 例如:我有3列名称ID,类型和值。我想根据'Type'计算'value'列。我使用DataRow Filter完成了它 - 首先获取唯一的'ID',然后为每个'type'计算值。这种逻辑非常复杂,需要更长的时间来处理。我在LINQ方面不是很好,所以我想知道我是否可以使用LINQ或其他任何方式做得更好?
数据表:
ID type value
--------------------------------
2 100 5
2 100 6
2 200 10
3 200 8
3 200 9
4 100 10
4 200 15
我正在寻找的输出是:
ID Type Value
2 100 11
2 200 10
3 200 17
4 100 10
4 200 15
答案 0 :(得分:5)
我认为你所寻找的是这样的。显然,在我使用<int>
的地方,您需要根据需要替换适当的类型。
var output = from row in table.AsEnumerable()
let id = row.Field<int>("ID")
let type = row.Field<int>("type")
group row by new { id, type } into grp
select new
{
ID = grp.Key.id,
Type = grp.Key.type,
Value = grp.Sum(r => r.Field<int>("value"))
};
这将导致相当简单的代码,但它不应该比一个编写良好的循环更具有效率(当然,如果你可以卸载它相反,这对数据库而言,通常会更好。)但是,所有事情都是平等的,Linq代码非常优化和高效。如果您对效率有疑问,衡量。运行现有代码(如果有的话)和答案代码,看看你的位置。
答案 1 :(得分:4)
为什么不在SQL中呢?
select id, type, sum(value) from TABLE group by id, type
答案 2 :(得分:3)
VB.NET(如果有人感兴趣的话):
Dim groups = From r In tbl
Group r By IDTypes = _
New With {Key .ID = CInt(r("ID")), _
Key .Type = CInt(r("Type"))}
Into Group
Select New With { _
.ID = IDTypes.ID, _
.Type = IDTypes.Type, _
.Value = Group.Sum(Function(grpRow) (CInt(grpRow("Value"))))}
这是测试数据:
Dim tbl As New DataTable
Dim row As DataRow
Dim rnd As New Random(Now.Millisecond)
tbl.Columns.Add(New DataColumn("ID", GetType(Int32)))
tbl.Columns.Add(New DataColumn("Type", GetType(Int32)))
tbl.Columns.Add(New DataColumn("Value", GetType(Int32)))
For i As Int32 = 1 To 1000000
row = tbl.NewRow
row("ID") = 2 * Rnd.Next(0, 6)
row("Type") = 100 * Rnd.Next(0, 6)
row("Value") = 5 * Rnd.Next(0, 11)
tbl.Rows.Add(row)
Next
1.000.000行的时间测量:
watch.Start()
Dim execute = groups.Any()
watch.Stop()
Console.WriteLine(String.Format("{0:00}:{1:00}:{2:00}.{3:00}", _
watch.Elapsed.Hours, _
watch.Elapsed.Minutes, _
watch.Elapsed.Seconds, _
watch.Elapsed.Milliseconds / 10))
结果(在2,26 GHZ Xeon,24GB):
~600毫秒分组+累计到~36“ID类型”
答案 3 :(得分:0)
假设您正在寻找某种分组,在值列上使用某种类型的聚合,您可以执行以下操作:
DataTable table = new DataTable();
var results = from row in table.AsEnumerable()
group row by new { Type = row.Field<int>("Type") } into groups
select new
{
Type = groups.Key.Type,
TotalValue = groups.Sum(x => x.Field<int>("Value"))
};