2011-09-23 19 views
4

LINQ让我疯狂。为什么下面的查询不会返回重复项,而它只能使用一个标识符?我的错误在哪里?使用LINQ获取两列的重复项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's answer :)

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性能。 我上面的代码中的下一个问题是从原始表中获取重复的行。 因为几乎每一行都有一个重复的(根据两个字段),结果DataTable包含100行中的99个,而不仅仅是19个重复值。我只需要选择第一个重复行并将它们与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为了保住另一列(S )放入相同的上下文中,并只返回分组后的第一行。通过这种方式,我可以使用CopyToDataTable从重复行创建一个DataTable。

只需几行代码(我可以保存第二个查询来查找原始表中的行),以查找多个列上的重复项并创建它们的DataTable。

回答

6

问题是这样的anonymous types work in VB - 默认情况下它们是可变的;只有Key属性包含在哈希和相等中。试试这个:

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

(在C#这不会是一个问题 - 匿名类型在C#总是在所有属性不变。)

+0

谢谢。我已经编辑了你的问题,因为在选择中已经太晚了,我首先需要它来对行进行分组。我希望我会记住这个事实。 –

+0

@TimSchmelter:哎呀,对不起。但它现在有效吗? –

+0

是的,重复项是正确的。但是现在我被困在接下来的行,我想加入与重复的原始表。结果('dupRows')是整个表格(100行),而不仅仅是dups(19行)。 –