在DataTable中标记非唯一行

时间:2010-12-06 09:54:13

标签: c# .net vb.net performance datatable

我有一个DataTable,我想检查三列中的值是否唯一。如果没有,最后一列应该填充值组合的第一次出现的行号。

例如,此表:

ID    Name    LastName    Age    Flag
-------------------------------------
1     Bart    Simpson     10      -
2     Lisa    Simpson      8      -
3     Bart    Simpson     10      -
4     Ned     Flanders    40      -
5     Bart    Simpson     10      -

应该导致这个结果:

Line  Name    LastName    Age    Flag
-------------------------------------
1     Bart    Simpson     10      -
2     Lisa    Simpson      8      -
3     Bart    Simpson     10      1
4     Ned     Flanders    40      -
5     Bart    Simpson     10      1

我通过使用两个嵌套的for循环迭代DataTable并比较这些值来解决这个问题。虽然这适用于少量数据,但当DataTable包含大量行时,会变得很慢

我的问题是:这个问题的最佳/最快解决方案是什么,因为数据量可以在100到20000行之间变化?
有没有办法用LINQ做到这一点? (我对它不太熟悉,但我想学习!)

2 个答案:

答案 0 :(得分:2)

我无法评论如何在C#/ VB中使用数据表进行此操作,但如果您可以将其全部移动到SQL,则查询将如下所示:

declare @t table (ID int, Name varchar(10), LastName varchar(10), Age int)
insert into @t values (1,     'Bart' ,   'Simpson',     10 )
insert into @t values (2,     'Lisa',    'Simpson' ,     8 )
insert into @t values (3,     'Bart',    'Simpson' ,    10 )
insert into @t values (4,     'Ned',     'Flanders' ,   40 )
insert into @t values (5 ,    'Bart',    'Simpson'   ,  10 )

select t.*,
(select min(ID) as ID
    from @t t2
    where t2.Name = t.Name
    and t2.LastName = t.LastName
    and t2.id < t.id)
from @t t

这里我已经为演示目的定义了一个表。我想你可以把它翻译成LINQ。

答案 1 :(得分:0)

好的,我想我自己得到了答案。根据James Wiseman的回答中的建议,我尝试了一些LINQ。

Dim myErrnrFnct = Function( current, first) If(first <> current, first, 0)
Dim myQuery = From row As DataRow In myDt.AsEnumerable _
                      Select New With { _
                        .LINE = row.Item("LINE"), _
                        .NAME = row.Item("NAME"), _
                        .LASTNAME = row.Item("LASTNAME"), _
                        .AGE = row.Item("AGE"), _
                        .FLAG = myErrnrFnct(row.Item("LINE"), myDt.AsEnumerable.First(Function(rowToCheck) _
                                                                                        rowToCheck.Item("NAME") = row.Item("NAME") AndAlso _
                                                                                        rowToCheck.Item("LASTNAME") = row.Item("LASTNAME") AndAlso _
                                                                                        rowToCheck.Item("AGE") = row.Item("AGE")).Item("LINE")) _
                      }

通过此查询,我得到了问题中描述的结果。 myErrnrFnct函数是必需的,因为如果没有其他行具有相同的值,我希望Flag列具有值0

要再次从myQuery中获取DataTable,我必须添加一些此处描述的扩展名:
How to: Implement CopyToDataTable Where the Generic Type T Is Not a DataRow
然后,这一行将做:

Dim myNewDt As DataTable = myQuery.CopyToDataTable()

这似乎工作得很好。有什么建议可以做得更好吗?