使用特定列执行 "except"
Perform "except" using particular columns
考虑 2 table 具有相同架构:
var yesterday = new DataTable();
yesterday.Columns.Add("id", typeof(int));
yesterday.Columns.Add("part_number", typeof(string));
yesterday.Columns.Add("description", typeof(string));
yesterday.Columns.Add("comment", typeof(string));
yesterday.Columns.Add("information", typeof(string));
yesterday.Columns.Add("data", typeof(string));
var today = yesterday.Clone();
添加一些数据:
//yesterday data has 3 rows
yesterday.Rows.Add(1, "IVD_002", "IVD_002_RED", "Some comment", "Some information","Some data");
yesterday.Rows.Add(2, "IVD_003", "IVD_003_RED", "Some comment", "Some information", "Some data");
yesterday.Rows.Add(3, "IVD_004", "IVD_004_RED", "Some comment", "Some information", "Some data");
//today's data has the same 3 rows
today.Rows.Add(1, "IVD_002", "IVD_002_RED", "Some comment", "Some information", "Some data");
today.Rows.Add(2, "IVD_003", "IVD_003_RED", "Some comment", "Some information", "Some data");
today.Rows.Add(3, "IVD_004", "IVD_004_RED", "Some comment", "Some information", "Some data");
让我们添加更多数据:
//The New Row:
//In the output table I expect to see only the following row. The "id" column is 5 whereas in previous records there is no row with id = 5, part_number = IVD_002, description = IVD_002_RED
today.Rows.Add(5, "IVD_002", "IVD_002_RED", "Some comment", "Some information", "Some data");
//Another New Row:
//I dont expect to see this row in the result table because we are doing except only on "id","part_number","description" columns
today.Rows.Add(1, "IVD_002", "IVD_002_RED", "ROSES ARE RED", "PEANUTS", "=)");
我的目标是从 "today" table 中获取行,但 "yesterday" table 中的行除外,但仅比较列 "id"、"part_number" ,"description".
非常感谢纯 LINQ 解决方案,w/o 循环。
我想我明白了。还有更好的方法吗?
var result = today.AsEnumerable()
.Where(r =>
today.AsEnumerable()
.Select(r =>
new { id = r["id"].ToString(), part_number = r["part_number"].ToString(), description = r["description"].ToString() })
.Except(yesterday.AsEnumerable()
.Select(r =>
new { id = r["id"].ToString(), part_number = r["part_number"].ToString(), description = r["description"].ToString() }))
.Contains(new { id = r["id"].ToString(), part_number = r["part_number"].ToString(), description = r["description"].ToString() }))
.CopyToDataTable();
我建议使用 !Any
。我更愿意将 yesterday
DataTable
转换为 HashSet
这样您就不会一直线性扫描 yesterday
以查找匹配项,但我不确定 UiPath 有哪些限制。
var result = today.AsEnumerable().Where(t => !yesterday.AsEnumerable().Any(y => (y["id"].Equals(t["id"]) &&
y["part_number"].Equals(t["part_number"]) &&
y["description"].Equals(t["description"]))))
.CopyToDataTable();
如果你可以使用 HashSet
,那么你可以这样做:
var yesterdayHash = yesterday.AsEnumerable().Select(y => new { id = (int)y["id"], partnum = y["part_number"].ToString(), desc = y["description"].ToString() }).ToHashSet();
var result2 = today.AsEnumerable().Where(t => !yesterdayHash.Contains(new { id = (int)t["id"], partnum = t["part_number"].ToString(), desc = t["description"].ToString() })).CopyToDataTable();
使用用于创建 Func
委托的静态 class Cast 帮助程序 return 匿名类型,您可以创建一个 lambda 变量来保存公共键表达式:
public static class To {
public static Func<TResult> Func<TResult>(Func<TResult> func) => func;
public static Func<T, TResult> Func<T, TResult>(Func<T, TResult> func) => func;
}
var selectorFn = To.Func((DataRow r) => new { id = r.Field<int>("id"), partnum = r.Field<string>("part_number"), desc = r.Field<string>("description") });
var yesterdayHash2 = yesterday.AsEnumerable().Select(selectorFn).ToHashSet();
var result3 = today.AsEnumerable().Where(t => !yesterdayHash2.Contains(selectorFn(t))).CopyToDataTable();
注意:我更喜欢在 DataRow
上使用 Field<>
扩展方法来获取强类型 DataTable
列值。
考虑 2 table 具有相同架构:
var yesterday = new DataTable();
yesterday.Columns.Add("id", typeof(int));
yesterday.Columns.Add("part_number", typeof(string));
yesterday.Columns.Add("description", typeof(string));
yesterday.Columns.Add("comment", typeof(string));
yesterday.Columns.Add("information", typeof(string));
yesterday.Columns.Add("data", typeof(string));
var today = yesterday.Clone();
添加一些数据:
//yesterday data has 3 rows
yesterday.Rows.Add(1, "IVD_002", "IVD_002_RED", "Some comment", "Some information","Some data");
yesterday.Rows.Add(2, "IVD_003", "IVD_003_RED", "Some comment", "Some information", "Some data");
yesterday.Rows.Add(3, "IVD_004", "IVD_004_RED", "Some comment", "Some information", "Some data");
//today's data has the same 3 rows
today.Rows.Add(1, "IVD_002", "IVD_002_RED", "Some comment", "Some information", "Some data");
today.Rows.Add(2, "IVD_003", "IVD_003_RED", "Some comment", "Some information", "Some data");
today.Rows.Add(3, "IVD_004", "IVD_004_RED", "Some comment", "Some information", "Some data");
让我们添加更多数据:
//The New Row:
//In the output table I expect to see only the following row. The "id" column is 5 whereas in previous records there is no row with id = 5, part_number = IVD_002, description = IVD_002_RED
today.Rows.Add(5, "IVD_002", "IVD_002_RED", "Some comment", "Some information", "Some data");
//Another New Row:
//I dont expect to see this row in the result table because we are doing except only on "id","part_number","description" columns
today.Rows.Add(1, "IVD_002", "IVD_002_RED", "ROSES ARE RED", "PEANUTS", "=)");
我的目标是从 "today" table 中获取行,但 "yesterday" table 中的行除外,但仅比较列 "id"、"part_number" ,"description".
非常感谢纯 LINQ 解决方案,w/o 循环。
我想我明白了。还有更好的方法吗?
var result = today.AsEnumerable()
.Where(r =>
today.AsEnumerable()
.Select(r =>
new { id = r["id"].ToString(), part_number = r["part_number"].ToString(), description = r["description"].ToString() })
.Except(yesterday.AsEnumerable()
.Select(r =>
new { id = r["id"].ToString(), part_number = r["part_number"].ToString(), description = r["description"].ToString() }))
.Contains(new { id = r["id"].ToString(), part_number = r["part_number"].ToString(), description = r["description"].ToString() }))
.CopyToDataTable();
我建议使用 !Any
。我更愿意将 yesterday
DataTable
转换为 HashSet
这样您就不会一直线性扫描 yesterday
以查找匹配项,但我不确定 UiPath 有哪些限制。
var result = today.AsEnumerable().Where(t => !yesterday.AsEnumerable().Any(y => (y["id"].Equals(t["id"]) &&
y["part_number"].Equals(t["part_number"]) &&
y["description"].Equals(t["description"]))))
.CopyToDataTable();
如果你可以使用 HashSet
,那么你可以这样做:
var yesterdayHash = yesterday.AsEnumerable().Select(y => new { id = (int)y["id"], partnum = y["part_number"].ToString(), desc = y["description"].ToString() }).ToHashSet();
var result2 = today.AsEnumerable().Where(t => !yesterdayHash.Contains(new { id = (int)t["id"], partnum = t["part_number"].ToString(), desc = t["description"].ToString() })).CopyToDataTable();
使用用于创建 Func
委托的静态 class Cast 帮助程序 return 匿名类型,您可以创建一个 lambda 变量来保存公共键表达式:
public static class To {
public static Func<TResult> Func<TResult>(Func<TResult> func) => func;
public static Func<T, TResult> Func<T, TResult>(Func<T, TResult> func) => func;
}
var selectorFn = To.Func((DataRow r) => new { id = r.Field<int>("id"), partnum = r.Field<string>("part_number"), desc = r.Field<string>("description") });
var yesterdayHash2 = yesterday.AsEnumerable().Select(selectorFn).ToHashSet();
var result3 = today.AsEnumerable().Where(t => !yesterdayHash2.Contains(selectorFn(t))).CopyToDataTable();
注意:我更喜欢在 DataRow
上使用 Field<>
扩展方法来获取强类型 DataTable
列值。