一覧形式のデータを保持するのに便利なDataTableクラスですが、これにLinqを使うと、ループでごちゃごちゃやっていた処理が、たった1行で済んでしまいます。
今回は、DataTableを扱う上で、知っておくと便利なLinqの使い方をご紹介します。
ちなみに、この記事ではカラムの事を列と表現しています。
便利な使い方
これから紹介するサンプルソースは、 dt という名前のDataTableインスタンスが、既に出来上がっているという前提です。
任意の列を配列に変換して返す
全ての列を取り出す場合は、次の様に書きます。
dt.AsEnumerable().Select(抽出対象).ToArray()
1 2 |
//全ての行の製品名の内容を配列にして取り出す var result = dt.AsEnumerable().Select(i=>i["製品名"]).ToArray(); |
dt.AsEnumerable() と書きましたが、これは dt.Rows.Cast<DataRow>().Select ~ のようにDataTableを DataRow にキャスト(型変換)する記述でもOKです。
1 2 |
//Cast<DataRow> を使った書き方 var result = dt.Rows.Cast<DataRow>().Select(i=>i["製品名"]).ToArray(); |
任意の列に値を代入する
特定の列に値を代入する(置き換える)場合は、次の様に書きます。
dt.AsEnumerable().Select(代入式).ToArray()
ポイントは末尾のToArray() です。
これが無いと内部的に処理はしてくれるものの、DataTableへの反映(書き戻し)が行われませんのでご注意ください。
ちなみに、ToArray()の代わりに ToList() でもOKです。
1 2 |
//全ての行の価格を35000円に置き換える dt.AsEnumerable().Select(i=>i["価格"] = "35000").ToArray(); |
DataTableの全ての列名を配列で返す
DataTableをDataColumnでキャストするとSelectの中で列名が参照できますので、これを利用します。
dt.Columns.Cast<DataColumn>().Select(DataColumnから取り出したいプロパティ).ToArray()
実際のサンプルは次の様になります。
1 2 |
//全ての列名を配列で返す var result = dt.Columns.Cast<DataColumn>().Select(i=>i.ColumnName).ToArray(); |
ColumnNameの代わりにDataType を指定すると、全ての列のデータ型が取得できます。
DataTableの全ての列名を変更する
DataTableの列名を変更することも可能です。
dt.Columns.Cast<DataColumn>().Select(代入式).ToArray()
1 2 |
//全ての列名に含まれているアンダースコアを抹消する dt.Columns.Cast<DataColumn>().Select(i=>i.ColumnName = i.ColumnName.Replace("_","")).ToArray(); |
条件を満たす行だけ抜き出してDataTableを作成する
特定の条件の行を抜き出したい場合、Where を使いますが、最後に CopyToDataTable() を付けてあげることで、抽出した結果からDataTableを作成してくれます。
dt.AsEnumerable().Where(抽出条件).CopyToDataTable()
1 2 |
//製品名に"10世代"という文字が含まれている行を抜き出してDataTableを作成する DataTable result = dt.AsEnumerable().Where(i=>i["製品名"].ToString().Contains("10世代")).CopyToDataTable(); |
同様のことはDataViewクラスを使っても出来ますが、3行になってしまいます。
1 2 3 4 |
//DataView の RowFilter を使ってデータを抜き出し、新しくDataTableを作成する var dv = new DataView(dt); dv.RowFilter="製品名 like '%10世代%'"; DataTable result = dv.ToTable(); |
無理やり1行に書く事も出来ます。
1 2 |
//上記と同じ内容を1行で書くなら、次のようになる DataTable reslut = new DataView(dt){ RowFilter="製品名 like '%10世代%'"}.ToTable(); |
処理速度は遅いですが、DataTableのSelect()メソッドでデータを抜き出して、CopyToDataTable()メソッドでDataTableにする方法もあります。
こちらはDataViewに比べて素直な書き方になります。
1 2 |
//DataTableに備わっているSelectメソッドによる抽出 DataTable result = dt.Select("製品名 like '%10世代%'").CopyToDataTable(); |
Linqの処理速度は高速ですが抽出条件の記述が煩雑になるので、場合によって使い分けが必要になります。
データ抽出の速度比較
LinqのWhere、DataViewのRowFilter、DataTableのSelectのそれぞれの方法について、簡単に速度を比較してみました。
ます小規模なDataTable(218行、12列)から、指定した条件で17行のデータを抽出した場合、LinkのWhereが最も速く、DataView.RowFilterが最も遅い結果となりました。
次に、比較的大きなDataTalbe(10万行、12列) から、12444行のデータを抽出した場合も、LinkのWhereが最も速く、DataView.RowFilterが最も遅い結果となりました。
以上様の結果から、DataTableの規模に関係なく Linq が最も速く、2番目に DataTable のSelectメソッド、一番遅いのが DataViewのRowFilter という結果となりました。
LinkのWhereの処理速度は、DataViewのRowFilterに比べて、小さなDataTableでは3倍以上、比較的大きなDataTableで2倍以上も高速であるという結果になりました。
まとめ
いかがでしたでしょうか。
Linqを使うと今までforループで数行記述が必要だった抽出処理が1行で書けてしまいます。
また、指定条件によるデータ抽出では、Linqが他の方法に比べて2~3倍速いということも分かりました。
あまり複雑な記述はよけいに見難くなりますが、単純なものだと可読性も上がります。
Linqが使えるところは、どんどん使っていきましょう。
コメント