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
andGetHashCode
methods on anonymous types are defined in terms of theEquals
andGetHashcode
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;
精彩评论