13

我有一个DataTable(目前有多个列,但如果它更容易,我可以抓住一列)。我想检查一个String值是否存在于DataTable. (我做了很多次,所以我希望它相当快。)

有什么好方法可以做到这一点?DataTable每次遍历行似乎是一种不好的方式。我可以将列转换为平面List/Array格式并使用内置函数吗?像myStrList.Contains("value")什么?

4

4 回答 4

23

您可以使用select来查找该值是否存在。如果是这样,它会返回行,否则不会。这里有一些示例代码可以帮助您。

Dim foundRow() As DataRow
foundRow = dt.Select("SalesCategory='HP'")
于 2013-01-21T17:52:58.187 回答
12

如果您的数据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

您可能还想研究使用SortedListorSortedDictionary类。这两个都是二叉树的实现。很难说所有这些选项中的哪一个在您的特定场景中最快。这完全取决于数据的类型、索引需要重建的频率、搜索的频率、索引中有多少行DataTable以及您需要对找到的项目做什么。最好的办法是在测试用例中尝试每一个,看看哪一个最适合你的需要。

于 2013-01-22T10:20:05.833 回答
11

您应该使用行过滤器DataTable.Rows.Find()而不是选择(选择不使用索引)。根据您的表结构,特别是如果您的相关字段被索引(本地),则任何一种方式的性能都应该比遍历所有行快得多。在 .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")

如果您的行类具有MyColumntype 属性String,则它变为:

CheckValue(myTable, Function(x) x.myColumn = "123")

上述方法的好处之一是您可以将计算字段输入到您的检查条件中,因为myColumn这里不需要匹配myColumn表/数据库中的物理字段。

于 2013-01-21T18:52:39.080 回答
1
bool exists = dt.AsEnumerable().Where(c => c.Field<string>("Author").Equals("your lookup value")).Count() > 0;
于 2015-05-12T04:52:12.207 回答