我有一个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做到这一点? (我对它不太熟悉,但我想学习!)
答案 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()
这似乎工作得很好。有什么建议可以做得更好吗?