Distinctの単一化条件をラムダ式で指定する

ようなものは無かったので、StackOverflowの内容を参考に作ってみた。

■動機
・Distinctの引数に、OrderBy等と同様にラムダ式を引数とするようにして使いたかった。
・しかし、Distinctの引数はIEqualityComparer(Of TSource)でしか取れない。
・GroupByではラムダ式を引数に取れるので理想に近いけど、次の理由により構文が冗長になるためなんとも。。
　　・戻り値リストの要素が絞り込んだプロパティ値しか持たない匿名オブジェクト？
　　　になる(SQLのGROUP BYのイメージ)
　　　⇒後続処理にて、絞り込み要素とは別の要素でごにょごにょしたい場合不便。
　　・リスト要素のプロパティ値でしか絞り込めない
　　　⇒リスト要素が辞書型の場合、事前に絞込み用のクラス型へ変換する必要がある。

■参考
StackOverflowの回答にてC#で紹介されているDistinctBy関数を
VB.NETでIEnumerableの拡張メソッドとして実装してみた。

http://stackoverflow.com/questions/1300088/distinct-with-lambda

■実装

```vbnet

Imports System.Runtime.CompilerServices

Module EnumerableExtention

    'IEnumerable型の拡張メソッドを定義
    <Extension()> _
    Public Iterator Function DistinctBy(Of TSource, TKey)(ByVal source As IEnumerable(Of TSource), keySelector As Func(Of TSource, TKey)) As IEnumerable(Of TSource)
        Dim knownKeys As New HashSet(Of TKey)

        For Each element As TSource In source
            If knownKeys.Add(keySelector(element)) Then
                Yield element
            End If
        Next
    End Function

End Module
```
■使い方

・Dictionaryの配列を単一化することが可能

```vbnet
    <TestMethod()> _
    Public Sub DistinctByTest_Dictinary()

        Const KEY_CODE As String = "Code"
        Const KEY_VALUE As String = "Value"

        Dim list = New List(Of Dictionary(Of String, String)) From _
                        { _
                         New Dictionary(Of String, String) From {{KEY_CODE, "A"}, {KEY_VALUE, "あああ"}}, _
                         New Dictionary(Of String, String) From {{KEY_CODE, "B"}, {KEY_VALUE, "びびび"}}, _
                         New Dictionary(Of String, String) From {{KEY_CODE, "A"}, {KEY_VALUE, "あああ"}}, _
                         New Dictionary(Of String, String) From {{KEY_CODE, "C"}, {KEY_VALUE, "ししし"}} _
                        }

        Dim codeEqualA = Function(item As Dictionary(Of String, String))
                              Return item(KEY_CODE) = "A"
                          End Function

        Assert.AreEqual(2, list.FindAll(codeEqualA).Count)

        Dim result = list.DistinctBy(Function(item) item(KEY_CODE)).ToList

        Assert.AreEqual(1, result.FindAll(codeEqualA).Count)
    End Sub
```

・複数項目で単一化することも可能

```vbnet
    Private Class CodeValue
        Public Property Code As String
        Public Property Code2 As String
        Public Property Value As String
    End Class

    <TestMethod()> _
    Public Sub DistinctByTest_Class()
        Dim list = New List(Of CodeValue) From _
            { _
             New CodeValue With {.Code = "A", .Code2 = "A", .Value = "あああ"}, _
             New CodeValue With {.Code = "A", .Code2 = "B", .Value = "ああび"}, _
             New CodeValue With {.Code = "B", .Code2 = "A", .Value = "びびあ"}, _
             New CodeValue With {.Code = "B", .Code2 = "B", .Value = "びびび"}, _
             New CodeValue With {.Code = "A", .Code2 = "A", .Value = "あああ"}, _
             New CodeValue With {.Code = "C", .Code2 = "C", .Value = "ししし"} _
            }

        Dim codeEqualA = Function(item As CodeValue)
                             Return item.Code = "A"
                         End Function

        Assert.AreEqual(3, list.FindAll(codeEqualA).Count)

        '複数項目(Code + Code2 の組み合わせ)で絞り込むことも可能
        Dim result = list.DistinctBy(Function(item) New With {Key item.Code, _
                                                              Key item.Code2}).ToList

        Assert.AreEqual(2, result.FindAll(codeEqualA).Count)
    End Sub
```