检查 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

您可能还想研究使用SortedListSortedDictionary 类。这两个都是二叉树的实现。很难说所有这些选项中的哪一个在您的特定场景中最快。这完全取决于数据的类型、索引需要重建的频率、搜索的频率、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 中选中

要检查数组是不是仅包含另一个数组中的元素,VB.NET

在 SQL 和 VB.NET 中检查日期是不是小于另一个

VB.net 在连接之前检查数据库是不是存在

如何检查 vb .net 项目的 sql server 中是不是存在数据库和表?

vb.net 中是不是有任何代码来检查打印机状态