VB.NETでLINQのグループ化


## 環境

* VB.NET
* .NET Framework 4.6

# VB.NETでLINQのグループ化(SUM)

VB.NETでGroupByのLINQの書き方を調べても全然ヒットしないので覚書。
特にメソッドのLINQは少ないので困る。

難しい話は置いておいて結論から先に、複数キーでグループ化するには、

* `New With`じゃなくて`Tuple.Create`を使用する。

```vbnet
Dim group = details.GroupBy(Function(g) Tuple.Create(g.Item, g.category))
```

* `New With`なら`Key`を付ける

```vbnet
Dim group = details.GroupBy(Function(g) new with{ Key g.Item, Key g.category})
```


## テストで使用したリストの型

Item,Category,Quantityをもつリストを作成して、
Item,Categoryをグループ化、Quantityを合計する。

リストは以下の型クラス。

```vbnet
    Class Items

        Public Property Item As String
        Public Property category As String
        Public Property Quantity As Integer

        Public Sub New(item As String, category As String, quantity As Integer)
            Me.Item = item
            Me.category = category
            Me.Quantity = quantity
        End Sub

    End Class
```

## 匿名型でGroupByをしてみる

ネットで漁ってC#例からVB.NETに書き換えてみた。
Hogehoge()すると一応LINQは動くのだけど、期待通りの結果にならない。

```vbnet
    Public Sub Hogehoge()

        Dim details As New List(Of Items)
        details.Add(New Items("A", "CateA", 1))
        details.Add(New Items("A", "CateA", 2))
        details.Add(New Items("B", "CateB", 1))

        Dim group = details.GroupBy(Function(g) New With(g.Item, g.category)).
            Select(Function(x) New With {.groupItem = x.Key.Item1, .groupCategory = x.Key.Item2, .sumQuantity = x.Sum(Function(s) s.Quantity)}).
            ToList

        For Each item In group
            Debug.WriteLine(item.groupItem & ", " & item.groupCategory & ", " & item.sumQuantity)
        Next

        'A, CateA, 1
        'A, CateA, 2 ' AのItemが3の1行になることを期待してた。
        'B, CateB, 1
        
    End Sub
```

# Tuple.Createを使う

`New With`の代わりに`Tuple.Create`を使用すると期待通り。

```vbnet

    Public Sub Hogehoge()

        Dim details As New List(Of Items)
        details.Add(New Items("A", "CateA", 1))
        details.Add(New Items("A", "CateA", 2))
        details.Add(New Items("B", "CateB", 1))

        Dim group = details.GroupBy(Function(g) Tuple.Create(g.Item, g.category)).
            Select(Function(x) New With {.groupItem = x.Key.Item1, .groupCategory = x.Key.Item2, .sumQuantity = x.Sum(Function(s) s.Quantity)}).
            ToList

        For Each item In group
            Debug.WriteLine(item.groupItem & ", " & item.groupCategory & ", " & item.sumQuantity)
        Next

        ' A, CateA, 3 ' 期待通りの動作!
        ' B, CateB, 1

    End Sub
```

# Keyを付ける

匿名型にKeyをつけると期待通り。

```vbnet

    Public Sub Hogehoge()

        Dim details As New List(Of Items)
        details.Add(New Items("A", "CateA", 1))
        details.Add(New Items("A", "CateA", 2))
        details.Add(New Items("B", "CateB", 1))

        Dim group = details.GroupBy(Function(g) New With(Key g.Item, Key g.category)).
            Select(Function(x) New With {.groupItem = x.Key.Item1, .groupCategory = x.Key.Item2, .sumQuantity = x.Sum(Function(s) s.Quantity)}).
            ToList

        For Each item In group
            Debug.WriteLine(item.groupItem & ", " & item.groupCategory & ", " & item.sumQuantity)
        Next

        ' A, CateA, 3 ' 期待通りの動作!
        ' B, CateB, 1
        
    End Sub
```

## 感想

* 頑張ってC#から変換しても思うように行かなかった。
* 自分のような.Net初心者はC#とVBの匿名型の挙動が違うので知らないと積む。
* 他にやり方がありそう。