読者です 読者をやめる 読者になる 読者になる

けさらんぱさらん

方向性は定めず、ただ思いつくままに

LINQでファイルの差分を抽出する

LINQ

LINQでファイルの差分を抽出したいと思います。

file01とfile02があります。
こんな感じ

file01

00000001,a,b,c,d,e,f,g
00000002,a,b,c,d,e,f,g
00000003,a,b,c,d,e,f,g
00000004,a,b,c,d,e,f,g
00000005,a,b,c,d,e,f,g
00000006,a,b,c,d,e,f,g
00000007,a,b,c,d,e,f,g
00000008,a,b,c,d,e,f,g
00000009,a,b,c,d,e,f,g
00000010,a,b,c,d,e,f,g

file02

00000001,a,b,c,d,e,f,h
00000002,a,b,c,d,e,f,i
00000003,a,b,c,d,e,f,g
00000004,a,b,c,d,e,f,g
00000005,a,b,c,d,e,f,g
00000006,a,b,c,d,e,f,g
00000007,a,b,c,d,e,f,g
00000008,a,b,c,d,e,f,g
00000009,a,b,c,d,e,f,g
00000011,a,b,c,d,e,f,g

ファイルには、同じ行もあれば更新されている行もあります。
最初のカラムがIDとなっています。
追加されている行も削除されている行もあります。
追加と削除は、同じIDがあるかどうかで判断します。

これを差分で出してファイルに書き出します。
書き出すファイルには、更新・追加・削除が分かるようにマークをつけます。

以下が、それを処理するコードです。

class Program
{
    static void Main( string[] args )
    {
        var lines1 = File.ReadLines( "file01.csv").ToList();
        var lines2 = File.ReadLines( "file02.csv").ToList();

        var timer =  new System.Diagnostics.Stopwatch();
        timer.Start();

        var tempAddData = lines2.Except( lines1, new ExistsCompare() );
        var file2Minus = lines2.Except( tempAddData );
        var tempDeleteData = lines1.Except( lines2, new ExistsCompare() );
        var file1Minus = lines1.Except( tempDeleteData );
        var tempUpdateData = file2Minus.Except( file1Minus);

        var addData = tempAddData.Select( l => l + ",insert" );
        var deleteData = tempDeleteData.Select( l => l + ",delete" );
        var updateData = tempUpdateData.Select( l => l + ",update" );

        File.WriteAllLines( "file03.csv", addData.Concat( deleteData ).Concat( updateData ) );

        timer.Stop();

        Console.WriteLine( timer.ElapsedMilliseconds );
        Console.ReadLine();
    }
}

// 頭の8桁だけで同一判定する
class ExistsCompare : IEqualityComparer<string>
{

    public bool Equals( string x, string y )
    {
        return x.Substring( 0, 8 ) == y.Substring( 0, 8 );
    }

    public int GetHashCode( string obj )
    {
        return obj.Substring(0,8).GetHashCode();
    }
}

結果はこんな感じのファイルが出力されます。

00000011,a,b,c,d,e,f,g,insert
00000010,a,b,c,d,e,f,g,delete
00000001,a,b,c,d,e,f,h,update
00000002,a,b,c,d,e,f,i,update

これより効率的にすっきり書く方法ってないですかね?