13

私はDataTable(現在複数の列を持っていますが、簡単にすれば1つの列だけをつかむことができます)があります。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

SortedListまたはSortedDictionaryクラスの使用を検討することもできます。これらは両方ともバイナリ ツリーの実装です。これらすべてのオプションのどれが特定のシナリオで最速になるかを言うのは困難です. それはすべて、データのタイプ、インデックスを再構築する必要がある頻度、検索する頻度、にある行の数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")

行クラスMyColumnに type のプロパティがある場合、次のStringようになります。

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

上記のアプローチの利点の 1 つは、計算されたフィールドをチェック条件にフィードできることです。これは、ここではテーブル/データベース内の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 に答える