2012年02月26日

.NETでDataTableの比較

今回は二つのDataTableの比較を行ってみます。二つのDataTableの中身が同じかどうか調べるというのは稀によくある事。まずはダメな例と、何の工夫もない例を挙げてみます。なお、以下で挙げる例は全て各セルの値だけを調べるものです。実際に使うときはDataTableがNULLじゃないか、列数や行数が同じかどうかを事前に調べる必要があります。

例1:ダメな例
private bool DataTableEqual(DataTable table1, DataTable table2)
{
return table1.Equals(table2);
}

例2:何の工夫もない例
private bool DataTableEqual(DataTable table1, DataTable table2)
{
var rowCount = table1.Rows.Count;
var columnCount = table1.Columns.Count;
for (int i = 0; i < rowCount; i++)
{
for (int j = 0; j < columnCount; j++)
{
if (!table1.Rows[i][j].Equals(table2.Rows[i][j]))
{
return false;
}
}
}
return true;
}


例1のダメな例では、参照を比較しているのでダメです。普通は各セルの値を比較したいですよね。
例2は素直なロジックです。プロパティへのアクセスを少しでも減らすため、列数(columnCount)や行数(rowCount)は変数に逃がしておきましょう。僅かですが速くなります。


ここからが本題です。
.NET Framework3.5からは以下のように簡単にかけます。おそらく現状ではこれがベストだと思います。

例3:ベストな例
private bool DataTableEqual(DataTable table1, DataTable table2)
{
return table1.AsEnumerable().SequenceEqual(table2.AsEnumerable(), DataRowComparer.Default);
}


DataRowComparerが.NET Framework3.5から追加されたクラスで、DataRowを値で比較してくれます。

更に一歩進めて、「全列を比較しないで特定の列だけ比較したい」場合のロジックも用意してみました。まあ、あまりそんな状況はなさそうですが・・・。例3:ベストな例のところでDataRowComparer.Defaultの代わりに自作のComparerクラスを用意すればいいんですけど、面倒なときは以下のような感じで。

例4:特定の列だけ比較する例
private bool DataTableEqual(DataTable table1, DataTable table2)
{
Func<DataRow, IEnumerable<object>> selector = row => new[] { row["Column0"], row["Column1"], row["Column2"], row["Column3"], row["Column4"], row["Column5"], row["Column6"], row["Column7"], row["Column8"], row["Column9"] };
return table1.AsEnumerable().SelectMany(selector).SequenceEqual(table2.AsEnumerable().SelectMany(selector));
}


SelectManyメソッドで行と列を1次元のデータ構造にばらし、SequenceEqualメソッドで比較します。row["Column0"]〜row["Column9"]のあたりに比較したい列を指定してください。


一応、実行速度を測定してみました。10列×10万行のテーブルを比較したときにかかる時間で、単位はミリ秒です。私の環境では以下のようになりました。

何の工夫もない例:434
ベストな例:47
特定の列だけ比較する例:272

「LINQを使うと遅くなるんじゃね?」って懸念も裏腹に、圧倒的なスピードです。DataRowComparerはそのために用意されたのでしょうから速いのも当たり前かもしれませんけど。





ラベル:.net LINQ
posted by ぺるたご at 15:08| Comment(0) | TrackBack(0) | 日記 | このブログの読者になる | 更新情報をチェックする
この記事へのコメント
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント:

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。

この記事へのトラックバック
×

この広告は1年以上新しい記事の投稿がないブログに表示されております。