我的目标:我有一个1 GB的csv文件,我试图总结一下。假设该文件具有“字段”/列A-M。我希望某些字段在另一个字段上小计,比如说A.我想要的结果是字段A中的每个值都有三个其他字段的小计 - 比如B,G和L.
问题:我正在尝试使用LINQ查询处理此问题,但会抛出Out of Memory异常。
这是我的疑问:
Dim summarizedRecs = From line In System.IO.File.ReadLines(filepath)
Skip 1
Let e = New aRecord(line)
Group e
By e.A
Into g = Group
Select summarizedR = New With {
A,
.TotalB = g.Sum(Function(x) x.B),
.TotalG = g.Sum(Function(x) x.G),
.TotalL = g.Sum(Function(x) x.L)}
Order By summarizedR.A
aRecord
是一个简单的类,它的构造函数接受一行文本并将该行解析为适当的字段。这很好。
此方法适用于较小的文件~100 MB。应用程序使用的内存在100 MB文件和1 GB文件的运行时间内增加。
我怀疑LINQ组不是我想要的,但我不确定另一种LINQ方法。有吗?
我认为LINQ会将所有e实例保留在组中。最后,我不需要e组。在将每个e的字段添加到适当的组之后,可以处理该e。我只想得到来自e组的结果小计。
我也一起跳过LINQ并使用Dictionary(Of T1,T2)成功实现了这一点。这样做,我读取每行文本,创建一个aRecord实例,并将其总计应用于词典中相应的键值对。在这种方法中,只有一个aRecord实例。这在内存方面是有效的 - 内存消耗水平并保持相对较低。
因此Dictionary方法适用于1 GB文件。是否有LINQ替代方案?
答案 0 :(得分:1)
坚持使用Dictionary
解决方案没有任何问题,但如果您想使用LINQ,可以使用Aggregate
:
Dim summarizedRecs = File.ReadLines(filepath) _
.Skip(1) _
.Select(Function(line) New aRecord(line))
.Aggregate(New Hashtable(), Function(acc, cur)
acc(cur.A) += cur : Return acc
End Function)
和aRecord
类,为了方便实现+
- 运算符:
Private Class aRecord
Public Property A As String
Public Property B As Integer
Public Property G As Integer
Public Property L As Integer
Public Shared Operator +(a As aRecord, b As aRecord) As aRecord
If a is Nothing Then Return b
Return New aRecord() With { _
.A = a.A, _
.B = a.B + b.B, _
.G = a.G + b.G, _
.L = a.L + b.L _
}
End Operator
End Class
我在这里使用Hashtable
代替Dictionary
,因为如果找不到特定密钥,Hashtable
会返回Nothing
,并在+
中滥用此事实} -operator(只是为了保存一些代码行)。
我也不知道您的aRecord
课程的其他方面,但在此示例中,我滥用它来存储累积的字段B
,G
和L
(再次,保存一些代码行。)
但是,在现实世界的应用程序中,我可能会使用一个简单的For Each
循环,而不是试图变得聪明。