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")
?
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.
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'")
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.
bool exists = dt.AsEnumerable().Where(c => c.Field<string>("Author").Equals("your lookup value")).Count() > 0;