【VB】LINQ ~ GroupBy編 ~

■ サンプルに使用するクラス・データ

* クラス
NotInheritable Class Company
    Public Property Id As String

    Public Property CountryCode As String

    Public Property FieldType As String

    Public Property Name As String

    Public Property Point As Integer
End Class
* データ
Dim values As New List(Of Company) From
{
    New Company With {.Id = "X001", .CountryCode = "JP", .FieldType = "Car",
    .Name = "Toyota", .Point = 34},
    New Company With {.Id = "X002", .CountryCode = "JP", .FieldType = "Industry",
    .Name = "Hitachi", .Point = 33},
    New Company With {.Id = "Y001", .CountryCode = "US", .FieldType = "IT",
    .Name = "Google", .Point = 49},
    New Company With {.Id = "Y002", .CountryCode = "US", .FieldType = "IT",
    .Name = "Yahoo", .Point = 38},
    New Company With {.Id = "X003", .CountryCode = "JP", .FieldType = "Industry",
    .Name = "Mitsubishi", .Point = 29},
    New Company With {.Id = "X004", .CountryCode = "JP", .FieldType = "Industry",
    .Name = "Toshiba", .Point = 17},
    New Company With {.Id = "X005", .CountryCode = "US", .FieldType = "Industry",
    .Name = "Motorola", .Point = 34},
    New Company With {.Id = "Z001", .CountryCode = "EU", .FieldType = "IT",
    .Name = "SAP", .Point = 40},
    New Company With {.Id = "X006", .CountryCode = "US", .FieldType = "IT",
    .Name = "Microsoft", .Point = 45},
    New Company With {.Id = "Z002", .CountryCode = "EU", .FieldType = "IT",
    .Name = "Nokia", .Point = 24}
}

■ サンプル1: GroupByのみ

Dim coms = values.GroupBy(Function(x) x.CountryCode).ToList()
For Each comValue In coms
    Debug.WriteLine("{0} {1}件", comValue.Key, comValue.Count)
Next

出力結果

JP 4件
US 4件
EU 2件

■ サンプル2: GroupBy + Max

* クエリ構文(Into:グループ化した後に絞り込む事ができる。SQLのHaving的な)
Dim coms = From com In values
           Group com By com.CountryCode Into groupCom = Group
           Select CountryCode, MaxPoint = groupCom.Max(Function(x) x.Point)

For Each comValue In coms
    Debug.WriteLine("{0} : {1}", comValue.CountryCode, comValue.MaxPoint)
Next
* メソッド構文
Dim coms = values.GroupBy(Function(x) x.CountryCode) _
    .Select(Function(g) New With
                {
                .CountryCode = g.Key,
                .MaxPoint = g.Max(Function(y) y.Point)
                })

For Each comValue In coms
    Debug.WriteLine("{0} {1}件", comValue.CountryCode, comValue.MaxPoint)
Next

出力結果

JP 34件
US 49件
EU 40件

補足:Linq結果を値をDictionary化するには...

* 「ToDictionary(Function(x) x.【Key値】)」で行う
Dim coms = From com In values
           Group com By com.CountryCode Into groupCom = Group
           Select New With
               {
               .CountryCode = CountryCode,
               .Point = groupCom.Max(Function(x) x.Point)
               }
' ★ここ★
Dim companies = coms.ToDictionary(Function(x) x.CountryCode)

For Each comValue In coms
    Debug.WriteLine("{0} {1}件", comValue.Key, comValue.Value)
Next

■ サンプル3: GroupBy(複合キー) + Sum

Dim companies =
   values.GroupBy(Function(group) New With
   {
      Key group.CountryCode,
      Key group.FieldType
   }) _
   .Select(Function(group) New Company() With
   {
      .CountryCode = group.Key.CountryCode,
      .FieldType = group.Key.FieldType,
      .Point = group.Sum(Function(x) x.Point)
   })
For Each companyValue In companies
   Debug.WriteLine("{0} {1} {2}",
      companyValue.CountryCode,
      companyValue.FieldType,
      companyValue.Point)
Next

出力結果

JP Car 34
JP Industry 79
US IT 132
US Industry 34
EU IT 64