检查 VB.net 的 DataTable 中是不是存在值的最简单/最快的方法?
Posted
技术标签:
【中文标题】检查 VB.net 的 DataTable 中是不是存在值的最简单/最快的方法?【英文标题】:Simplest/fastest way to check if value exists in DataTable in VB.net?检查 VB.net 的 DataTable 中是否存在值的最简单/最快的方法? 【发布时间】:2013-01-04 20:04:24 【问题描述】:我有一个DataTable
(目前有多个列,但如果它更容易,我可以只抓取一列)。我想检查String
的值是否存在于DataTable
的列中。 (我做了很多次,所以我希望它相当快。)
有什么好的方法可以做到这一点?每次都遍历DataTable
行似乎是个坏方法。我可以将列转换为平面 List/Array
格式,并使用内置函数吗? myStrList.Contains("value")
之类的东西?
【问题讨论】:
您是否多次搜索相同的、不变的DataTable?如果是这样,将数据放入某种索引数据结构可能会更快,例如哈希表、树或排序数组(用于二进制搜索)。但是,如果表中的数据不断变化,则您必须不断重建索引,这将使其一文不值。 @StevenDoggart 是的,DT 在获取后不会改变。你有使用哈希表/排序数组的例子吗?数据只是一个字符串列表。 【参考方案1】:您可以使用select
来查找该值是否存在。如果是这样,它会返回行,否则不会。这里有一些示例代码可以帮助您。
Dim foundRow() As DataRow
foundRow = dt.Select("SalesCategory='HP'")
【讨论】:
【参考方案2】:如果您的DataTable
中的数据不经常更改,并且您多次搜索DataTable
,并且您的DataTable
包含许多行,那么构建您自己的数据可能会快很多数据的索引。
执行此操作的最简单方法是按键列对数据进行排序,以便您可以对排序列表进行二进制搜索。例如,您可以像这样构建索引:
Private Function BuildIndex(table As DataTable, keyColumnIndex As Integer) As List(Of String)
Dim index As New List(Of String)(table.Rows.Count)
For Each row As DataRow in table.Rows
index.Add(row(keyColumnIndex))
Next
index.Sort()
Return index
End Function
然后,您可以通过二分查找快速检查索引中是否存在值,如下所示:
Private Function ItemExists(index As List(Of String), key As String) As Boolean
Dim index As Integer = index.BinarySearch(key)
If index >= 0 Then
Return True
Else
Return False
End If
End Function
你也可以用一个简单的字符串数组来做同样的事情。或者,您可以使用 Dictionary
对象(它是哈希表的实现)来构建您的 DataTable
的哈希索引,例如:
Private Function BuildIndex(table As DataTable, keyColumnIndex As Integer) As Dictionary(Of String, DataRow)
Dim index As New Dictionary(Of String, DataRow)(table.Rows.Count)
For Each row As DataRow in table.Rows
index(row(keyColumnIndex)) = row
Next
Return index
End Function
然后,您可以获得与给定键匹配的DataRow
,如下所示:
Dim index As Dictionary(Of String, DataRow) = BuildIndex(myDataTable, myKeyColumnIndex)
Dim row As DataRow = Nothing
If index.TryGetValue(myKey, row) Then
' row was found, can now use row variable to access all the data in that row
Else
' row with that key does not exist
End If
您可能还想研究使用SortedList
或SortedDictionary
类。这两个都是二叉树的实现。很难说所有这些选项中的哪一个在您的特定场景中最快。这完全取决于数据的类型、索引需要重建的频率、搜索的频率、DataTable
中有多少行以及您需要对找到的项目做什么。最好的办法是在测试用例中尝试每一个,看看哪一个最适合您的需要。
【讨论】:
谢谢,SortedList
很好用。出于某种原因,标准 List
不起作用 - 即使字符串在列表中,它也会不断返回负索引。
您将如何解决表更新问题(添加/删除行)?
当您这样做时,您需要重新生成索引,或者您需要对索引进行相同的更改。因此,例如,当添加新行时,您需要将其添加到 DataTable 和索引中,或者在添加行后重新生成整个索引。
重新生成整个索引可能很耗时,尤其是对于大型表。如果您使用索引更新,您还需要编写多少代码?
是的,重新生成索引肯定会更慢。如果不知道你在做什么的所有细节,这很难回答。但是,要考虑的另一件事是:您是否需要在断开连接的DataTable
中实际执行所有这些操作?如果您连接到数据库,您可能会发现简单地重新查询数据库会更快。据推测,数据库已经拥有所有必要的索引,因此您不需要自己生成内存索引。【参考方案3】:
您应该使用 row filter 或 DataTable.Rows.Find() 而不是 select (select does not use indexes)。根据您的表结构,特别是如果您的相关字段被索引(本地),任何一种方式的性能都应该比遍历所有行快得多。在 .NET 中,一组字段必须是 PrimaryKey 才能被索引。
如果您的字段没有被索引,我会避免选择和行过滤器,因为除了类复杂性的开销之外,它们不提供编译时检查您的条件的正确性。如果它很长,您可能最终会花费大量时间偶尔调试它。
最好严格输入您的支票。首先定义了一个底层类型,你也可以定义这个辅助方法,以后可以转换为DataTable
类的扩展方法:
Shared Function CheckValue(myTable As DataTable, columnName As String, searchValue As String) As Boolean
For row As DataRow In myTable.Rows
If row(columnName) = searchValue Then Return True
Next
Return False
End Function
或更通用的版本:
Shared Function CheckValue(myTable As DataTable, checkFunc As Func(Of DataRow, Boolean)) As Boolean
For Each row As DataRow In myTable.Rows
If checkFunc(row) Then Return True
Next
Return False
End Function
及其用法:
CheckValue(myTable, Function(x) x("myColumn") = "123")
如果您的行类具有 String
类型的 MyColumn
属性,则它变为:
CheckValue(myTable, Function(x) x.myColumn = "123")
上述方法的一个好处是您可以将计算字段输入到您的检查条件中,因为这里的myColumn
不需要匹配表/数据库中的物理myColumn
。
【讨论】:
您也可以使用AsEnumerable()
(link) 和Any()
方法。
有没有办法在行中搜索一对值?也就是说col2 = "somestring" and col3 = an integer?
@htm11h:是的,只需应用不同的功能,即Function(x) x.col2 = "somestring" and x.col3 = 123
我发现在根据我的搜索条件创建DataView
后,重复调用DataTable.Select
会快得多。这使我相信DataTable.Select
将使用由DataView
创建的索引。
如果我想使用它但要找到一个类似于字符串的值怎么办?是 CheckValue(myTable, Function(x) x("myColumn") like "somevaluehere") 还是 CheckValue(myTable, Function(x) x("myColumn") = "*somevaluehere") ?【参考方案4】:
bool exists = dt.AsEnumerable().Where(c => c.Field<string>("Author").Equals("your lookup value")).Count() > 0;
【讨论】:
这将检查列作者是否在数据表的任何行中具有值“您的查找值”以上是关于检查 VB.net 的 DataTable 中是不是存在值的最简单/最快的方法?的主要内容,如果未能解决你的问题,请参考以下文章
VB.NET - 检查子节点是不是在 TreeView 中选中