在DataTable中标记非唯一行

5
我有一个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个回答

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)。不过我更喜欢一个不需要SQL的解决方案。我会尝试在LINQ中实现这样的功能。 - Philipp Grathwohl

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,我必须添加一些扩展,如下所述:
如何实现CopyToDataTable,其中通用类型T不是DataRow
然后,这行代码就可以了:

Dim myNewDt As DataTable = myQuery.CopyToDataTable()

这似乎很好用。有没有更好的建议?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接