1

私の目標: 要約しようとしている 1 GB の csv ファイルがあります。ファイルに「フィールド」/列 AM があるとします。特定のフィールドを別のフィールド (A など) で小計したいと思います。結果は、フィールド A の各値と、他の 3 つのフィールド (B、G、L など) の小計です。

問題: LINQ クエリでこれを処理しようとしていますが、メモリ不足の例外がスローされます。

これが私のクエリです:

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 のインスタンスを作成し、その合計を Dictionary 内の適切なキーと値のペアに適用します。このアプローチでは、aRecord のインスタンスは 1 つだけです。これはメモリに関して効率的です。消費されるメモリは横ばいになり、比較的低く抑えられます。

したがって、Dictionary アプローチは 1 GB のファイルで機能します。しかし、LINQの代替手段はありますか?

4

1 に答える 1

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)

および便宜上 -operator を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

特定のキーが見つからなかった場合にaが返されるので、Hashtableここでは代わりにa を使用し、 -operator でこの事実を悪用します (コードのいくつかの行を節約するためだけに)。DictionaryHashtableNothing+

また、あなたのクラスが他の方法で何をするかはわかりませんaRecordが、この例では、蓄積されたフィールドBG、およびL(コードのいくつかの行を節約するために) を格納するためにそれを悪用します。

しかし、実際のアプリケーションでは、For Each賢くしようとするのではなく、おそらく単純なループを使用するでしょう。

于 2013-09-18T13:47:59.030 に答える