开发者

Compare two DataTable Multi fields

        DataTable dt1 = new DataTable();
        DataTable dt2 = new DataTable();

        dt1.Columns.Add("id");
        dt2.Columns.Add("id");

        dt1.Columns.Add("val1");
        dt2.Columns.Add("val1");

        dt1.Columns.Add("val2");
        dt1.Columns.Add("val2");


        dt1.Rows.A开发者_如何学运维dd(new string[] { "1", "a", "a1" });
        dt1.Rows.Add(new string[] { "2", "b", "b1" });
        dt1.Rows.Add(new string[] { "", "b", "b1" });
        dt1.Rows.Add(new string[] { "4", "", "c1" });


        dt2.Rows.Add(new string[] { "1", "a", "a1" });
        dt2.Rows.Add(new string[] { "2", "b", "b1" });
        dt2.Rows.Add(new string[] { "3", "c", "c1" });
        dt2.Rows.Add(new string[] { "3", "c", "c1" });
        dt2.Rows.Add(new string[] { "4", "d", "d1" });
        dt2.Rows.Add(new string[] { "5", "e", "e1" });

result should contain only values which are not present in dt1. Can we do this with linq


Yes, you can do this with LINQ, I'd do this:

var dataRows1 = st1.AsEnumerable().Select(r => new { 
    Id = r["id"], Val1 = r["val1"], Val2 = r["val2"] });

var dataRows2 = st2.AsEnumerable().Select(r => new { 
    Id = r["id"], Val1 = r["val1"], Val2 = r["val2"] });

This gives you IEnumerable<T> of anonymous types which can be compared against. Then, you can do this:

var dt2NotInDt1 = dataRows2.Where(r2 => !dataRows1.Any(r1 => r1.Equals(r2));

Note, that this assumes that your comparison criteria is all the values in the rows (id included).

Also note the call to Equals. Anonymous types override the Equals method to provide a value comparison across all the properties of the anonymous type. From the "Anonymous Types" section of the C# Programming Guide:

Because the Equals and GetHashCode methods on anonymous types are defined in terms of the Equals and GetHashcode methods of the properties, two instances of the same anonymous type are equal only if all their properties are equal.

You can simplify this logic depending on what the constraints are. For example, if there is a primary key (or some sort of unique row identifier) you could place the rows in a dictionary keyed on that value and then perform the lookup based on that.

In your case, assuming id is unique, you could do this (after the first two lines at the top):

var dataRows1Map = dataRows1.ToDictionary(r => r.Id);

That will give you a map which you can then do a lookup on (I'm switching to query syntax, as I believe it's a little more readable here).

var dt2NotInDt1 = 
    for r2 in dataRows2
    let r1Exists = dataRows1Map.ContainsKey(r2.Id)
    let r1 = r1Exists ? dataRows1Map[r2.Id] : null
    where 
        // Rows that don't have a primary key in the first set.
        !r1Exists ||
        // Rows that are different.
        !r1.Equals(r2)
    select r2;
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜