4

LINQ は私を夢中にさせます。次のクエリが重複を返さないのはなぜですか? 私のエラーはどこですか?

' generate some test-data '
Dim source As New DataTable
source.Columns.Add(New DataColumn("RowNumber", GetType(Int32)))
source.Columns.Add(New DataColumn("Value1", GetType(Int32)))
source.Columns.Add(New DataColumn("Value2", GetType(Int32)))
source.Columns.Add(New DataColumn("Text", GetType(String)))
Dim rnd As New Random()
For i As Int32 = 1 To 100
    Dim newRow = source.NewRow
    Dim value = rnd.Next(1, 20)
    newRow("RowNumber") = i
    newRow("Value1") = value
    newRow("Value2") = (value + 1)
    newRow("Text") = String.Format("RowNumber{0}-Text", i)
    source.Rows.Add(newRow)
Next
' following query does not work, it always has Count=0 '
' although it works with only one identifier '
Dim dupIdentifiers = From row In source
         Group row By grp = New With {.Val1 = row("Value1"), .Val2 = row("Value2")}
         Into Group
         Where Group.Count > 1
         Select idGroup = New With {grp.Val1, grp.Val2, Group.Count}

編集: @Jon Skeetの回答のおかげで、以下は完全な解決策です:)

Dim dupKeys = From row In source
        Group row By grp = New With {Key .Val1 = CInt(row("Value1")), Key .Val2 = CInt(row("Value2"))}
        Into Group Where Group.Count > 1
        Select RowNumber = CInt(Group.FirstOrDefault.Item("RowNumber"))

Dim dupRows = From row In source
        Join dupKey In dupKeys 
        On row("RowNumber") Equals dupKey 
        Select row

If dupRows.Any Then
    ' create a new DataTable from the first duplicate rows '
    Dim dest = dupRows.CopyToDataTable
End If

keyグループ化の主な問題は、それらをプロパティにする必要があることでした。上記のコードの次の問題は、元のテーブルから重複した行を取得することでした。ほぼすべての行に (2 つのフィールドによると) 重複があるため、結果の DataTable には、19 の重複値だけでなく、100 行中 99 行が含まれていました。最初の重複行のみを選択し、それらを PK の元のテーブルに結合する必要がありました。

Select RowNumber = CInt(Group.FirstOrDefault.Item("RowNumber"))

これは私の場合は機能しますが、複合キーしかない場合、元のテーブルから重複のみを選択する方法を誰かが説明してくれるかもしれません。


編集:私は質問の最後の部分に自分で答えたので、ここに私が必要とするすべてがあります:

Dim dups = From row In source
         Group By grp = New With {Key .Value1 = CInt(row("Value1")), Key .Value2 = CInt(row("Value2"))}
         Into Group Where Group.Count > 1
         Let Text = Group.First.Item("Text")
         Select Group.First

If dups.Any Then
      Dim dest = dups.CopyToDataTable
End If

他の列を同じコンテキストに保持し、グループ化された複製の最初の行のみを返すために、 Let-Keywordが必要でした。このようCopyToDataTableにして、重複した行から DataTable を作成するために使用できます。

複数の列の重複を見つけて、それらの DataTable を作成するために、全体でわずか数行のコード (元のテーブルの行を見つけるために 2 番目のクエリを保存できます)。

4

1 に答える 1

6

問題は、匿名型が VB で動作する方法です。既定では変更可能です。Keyハッシュと等価にはプロパティのみが含まれます。これを試して:

Group row By grp = New With {Key .Val1 = row("Value1"), Key .Val2 = row("Value2")}

(C# では、これは問題になりません。C# の匿名型は、すべてのプロパティで常に不変です。)

于 2011-09-23T14:52:43.117 に答える