web-dev-qa-db-fra.com

Le moyen le plus simple / le plus rapide de vérifier si la valeur existe dans DataTable dans VB.net?

J'ai un DataTable (actuellement avec plusieurs colonnes mais je pourrais simplement saisir une colonne si cela facilite les choses). Je veux vérifier si une valeur String existe dans une colonne de DataTable. (Je le fais plusieurs fois, donc je veux que ce soit assez rapide.)

Quelle est la bonne façon de procéder? Parcourir chaque fois les lignes DataTable semble être une mauvaise façon. Puis-je convertir la colonne au format plat List/Array Et utiliser une fonction intégrée? Quelque chose comme myStrList.Contains("value")?

8
DisgruntledGoat

Si les données de votre DataTable ne changent pas très souvent, et que vous effectuez une recherche dans le DataTable plusieurs fois et que votre DataTable contient de nombreuses lignes, alors ce sera probablement un beaucoup plus rapide pour construire votre propre index pour les données.

La manière la plus simple de procéder consiste à trier les données par la colonne clé afin de pouvoir ensuite effectuer une recherche binaire sur la liste triée. Par exemple, vous pouvez créer un index comme celui-ci:

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

Ensuite, vous pouvez vérifier si une valeur existe rapidement dans l'index avec une recherche binaire, comme ceci:

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

Vous pouvez également faire la même chose avec un simple tableau de chaînes. Ou, vous pouvez utiliser un objet Dictionary (qui est une implémentation d'une table de hachage) pour construire un index de hachage de votre DataTable, par exemple:

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

Ensuite, vous pouvez obtenir le DataRow correspondant pour une clé donnée, comme ceci:

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

Vous pouvez également envisager d'utiliser la classe SortedList ou SortedDictionary. Ces deux sont des implémentations d'arbres binaires. Il est difficile de dire laquelle de toutes ces options sera la plus rapide dans votre scénario particulier. Tout dépend du type de données, de la fréquence à laquelle l'index doit être reconstruit, de la fréquence à laquelle vous le recherchez, du nombre de lignes dans le DataTable et de ce que vous devez faire avec les éléments trouvés. La meilleure chose à faire serait d'essayer chacun dans un cas de test et de voir lequel fonctionne le mieux pour ce dont vous avez besoin.

10
Steven Doggart

Vous pouvez utiliser select pour déterminer si cette valeur existe ou non. Si c'est le cas, il renvoie des lignes ou il ne le fera pas. Voici quelques exemples de code pour vous aider.

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

Vous devez utiliser filtre de ligne ou DataTable.Rows.Find () au lieu de select ( select n'utilise pas d'index ). En fonction de la structure de votre table, en particulier si votre champ en question est indexé (localement), les performances dans les deux sens devraient être beaucoup plus rapides que de parcourir toutes les lignes. Dans .NET, un ensemble de champs doit être un PrimaryKey pour devenir indexé.

Si votre champ n'est pas indexé, j'éviterais à la fois le filtre de sélection et le filtre de ligne, car à part la surcharge de la complexité de la classe, ils n'offrent pas de vérification du temps de compilation pour l'exactitude de votre condition. Si elle est longue, vous risquez de passer beaucoup de temps à la déboguer de temps en temps.

Il est toujours préférable de faire taper strictement votre chèque. Après avoir défini un type sous-jacent, vous pouvez également définir cette méthode d'assistance, que vous pourrez convertir ultérieurement en méthode d'extension de la classe 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

ou une version plus générique de celui-ci:

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

et son utilisation:

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

Si votre classe de ligne a la propriété MyColumn de type String, elle devient:

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

L'un des avantages de l'approche ci-dessus est que vous pouvez insérer des champs calculés dans votre condition de vérification, car myColumn ici n'a pas besoin de correspondre à un myColumn physique dans la table/base de données.

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