我们需要将以下逻辑形式的数据存储到类中:
"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
答案 0 :(得分: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}}}
}
结果:
答案 1 :(得分:-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
类定义。有很大的benefits when using immutable classes,您应该同意直接暴露您的会员变量没有属性被认为是不好的做法。
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
会为稀疏的数据填充提供更好的支持,但原始问题中没有定义。这些例子从一个单调开始。
有几种方法可以执行分组,我将它分成三个简单的步骤,我将很容易遵循。记住,这都是懒惰的评估。
首先,将数据展平为月份级别,并将月份编号合并到序列中。
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})
})