Самый простой / быстрый способ проверить, существует ли значение в DataTable in VB.net?

у меня есть DataTable (в настоящее время с несколькими столбцами, но я мог бы просто захватить один столбец, если это делает его легче). Я хочу проверить, если String значение существует в столбце DataTable. (Я делаю это много раз, поэтому я хочу, чтобы это было достаточно быстро.)

какой хороший способ сделать это? Переборем DataTable строки каждый раз кажется плохим способом. Могу ли я преобразовать столбец в flat List/Array форматировать и использовать встроенную функцию? Что-то вроде myStrList.Contains("value")?

4 ответов


если данные в вашей 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, и что вам нужно сделать с найденными предметами. Лучше всего было бы попробовать каждый из них в тестовом случае и посмотреть, какой из них лучше всего подходит для того, что вам нужно.


можно использовать select найти ли это значение или нет. Если это так,он возвращает строки или не будет. Вот пример кода, который вам поможет.

Dim foundRow() As DataRow
foundRow = dt.Select("SalesCategory='HP'")

вы должны использовать фильтр строк или DataTable.Строки.Find () вместо select (select не использует индексы). В зависимости от структуры таблицы, в частности если поле индексируется (локально), производительность в любом случае должна быть намного быстрее, чем цикл через все строки. В .NET набор полей должен быть свойства primarykey чтобы стать проиндексированы.

если ваше поле не индексируется, I избежать фильтра select и row, потому что, помимо накладных расходов сложности класса, они не предлагают проверку времени компиляции на правильность вашего условия. Если он длинный, вы можете потратить много времени на его отладку время от времени.

всегда предпочтительнее, чтобы ваш чек был строго напечатан. Сначала определив базовый тип, вы также можете определить этот вспомогательный метод, который можно преобразовать в метод расширения 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")

если ваш класс строки MyColumn свойство типа String в:

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

одним из преимуществ вышеуказанного подхода является то, что вы можете подавать вычисляемые поля в свое условие проверки, так как myColumn здесь не нужно соответствовать физическому myColumn в таблице/базе.


bool exists = dt.AsEnumerable().Where(c => c.Field<string>("Author").Equals("your lookup value")).Count() > 0;