0

以下の論理形式のデータをクラスに格納する必要があります。

"description 1", "activity A", "service A", Month 1 cost, month 2 cost, month 3 cost etc....

だから私は以下のようなクラスオブジェクトを持っています:

Public Class EntityTableRow
    Public Description As String
    Public Activity As String
    Public M1 as Double
    Public M2 as Double
    .....
End Class

M... プロパティは、ソース データ (Excel データ ソース) に含まれる月数に応じて毎月のコストを保持します。論理的には、上記のクラスは上記の論理形式と同様のデータを保持します

次に、同じ列に基づいて行をグループ化し、月のコストを合計する必要があります。

このために、私は以下のLinqクエリを使用しようとしています:

Dim a As New List(Of EntityTableRow) 
        a = myTable1.TableRows 
        Dim lFinal2 = From el In a Group el By Key = New With {Key el.Description, Key el.Activity} Into Group _ 
                      Select New With {.Activity = Key.Description, _ 
                                       .Country = Key.Activity, _ 
                                       .M1 = Group.Sum(Function(x) x.M1), _ 
                                       .M2 = Group.Sum(Function(x) x.M2)} 

これは正常に機能しているようですが、月のコストを辞書に保存し、グループ化された行を取得し、異なる月の列で合計する必要がある以下の変更されたクラスに対して、上記の Linq クエリを変更するにはどうすればよいですか?

Public Class EntityTableRow
        Public Description As String
        Public Activity As String
        Public MonthCosts As New Dictionary(Of Integer, Double)
    End Class
4

2 に答える 2

1
Dim lFinal2 = From el In a
              Group el By Key = New With {Key el.Description, Key el.Activity} Into Group
              Select New With {
                  .Activity = Key.Description,
                  .Country = Key.Activity,
                  .MonthCost =
                      (From k In Group.SelectMany(Function(g) g.MonthCosts.Keys).Distinct()
                       Select New With {
                            .Month = k,
                            .Sum = Group.Sum(Function(g) If(g.MonthCosts.ContainsKey(k), g.MonthCosts(k), 0))
                       }).ToDictionary(Function(i) i.Month, Function(i) i.Sum)
              }

簡単なテストデータ:

Dim a As New List(Of EntityTableRow) From {
    New EntityTableRow With {.Activity = "A", .Description = "D", .MonthCosts = New Dictionary(Of Integer, Double) From {{1, 20}, {2, 20}, {3, 20}}},
    New EntityTableRow With {.Activity = "A", .Description = "D", .MonthCosts = New Dictionary(Of Integer, Double) From {{2, 20}, {3, 20}, {4, 20}}}
}

そして結果: ここに画像の説明を入力

于 2013-03-19T17:32:54.470 に答える
-3

最初のデータ型は次の形式をとる必要があるように思えます

Public Class EntityTableRow
    Public Description As String
    Public Activity As String
    Public MonthCosts As IEnumerable(Of Decimal)
End Class

IEnumerable(Of Decimal)注文のグループから選択する方法を説明します。これは、IEnumerableが実装者に応じて順序付けられたデータを表すことができることを示しているはずです。まず、EntityTableRowクラス定義を展開します。不変クラスを使用することには大きな利点があり、プロパティなしでメンバー変数を直接公開することは悪い習慣と見なされることに同意する必要があります。

Public Class EntityTableRow

    Private ReadOnly _descritption As String
    Private ReadOnly _activity As String
    Private ReadOnly _monthCosts As IList(Of Decimal)

    Public Sub New( _
            ByVal description As String,
            ByVal activity As String, _
            ByVal monthCosts As IEnumerable(Of Decimal))
        Me._description = description
        Me._activity = activity
        Me._monthCosts = New List(Of Decimal)(monthCosts)
    End Sub

    Public ReadOnly Property Description() As String
        Get
            Return Me._description
        End Get
    End Property

    Public ReadOnly Property Activity() As String
        Get
            Return Me._activity
        End Get
    End Property

    Public ReadOnly Property MonthCosts() As IEnumerable(Of Decimal)
        Get
            Return Me._monthCosts
        End Get
    End Property
End Class

クラスは公開するだけですIEnumerable(Of Decimal)が、このシーケンスは順序付けられたデータを表していることがわかります。次に、linqをIEnumerable(Of EntityTableRow)使用して、この定義を使用してデータをグループ化する方法を示します。

まず、いくつかのテストデータを作成します。

Dim testData As IEnumerable(Of EntityTableRow) = _
    {
        New EntityTableRow("A", "B", New Decimal() {20, 20, 20}),
        New EntityTableRow("A", "B", New Decimal() {Nothing, 20, 20, 20}),
        New EntityTableRow("C", "D", New Decimal() {10, 20, Nothing, 40}),
        New EntityTableRow("C", "D", New Decimal() {50, 60})
    }

この時点で、私IListはデータのまばらな母集団に対してより良いサポートを提供するだろうと主張しますが、それは元の質問では定義されていません。例は1つから単調に始まります。

グループ化を実行するにはいくつかの方法があります。簡単に実行できるように、3つの簡単な手順に分けます。これはすべて遅延評価されていることを忘れないでください。

まず、データを月レベルにフラット化し、月番号をシーケンスに組み込みます。

 Dim allCosts = testData.SelectMany( _
     Function(r) r.MonthCosts.Select( _
         Function(c, i) New With {r.Descriptionr, r.Activity, .Month = i, .Cost = c}))

Select注文から月を推測するためにインデックス拡張を使用していることに注意してください。

次に、アクティビティ、説明、月ごとにコストをグループ化して合計します。

Dim groupedCosts = allCosts.GroupBy( _
    Function(r) New With {r.Activity, r.Description, r.Month},
    Function(k, s) New With
        {
            k.Description,
            k.Activity,
            k.Month,
            .TotalCost = s.Sum(Function(r) r.Cost)
        })

これにより、実際に必要な情報が得られます。それでも望ましい場合は、説明とアクティビティで月を再グループ化できます。

Dim groupedDescriptionActivities = groupedCosts.GroupBy( _
    Function(r) New With {r.Description, r.Activity}, _
    Function(k, s) New With
        {
            k.Description,
            k.Activity,
            .MonthCosts = s.Select(Function(r) New With {r.Month, r.TotalCost})
        })
于 2013-03-19T17:30:25.157 に答える