确定数据表中的重复项
我有一个从CSV文件加载的数据表。 我需要根据数据表中的两列( product_id
和owner_org_id
)确定哪些行是重复的。 一旦我确定了,我就可以使用该信息来构建我的结果,这是一个只包含非唯一行的数据表,以及一个只包含唯一行的数据表。
我在这里看了其他的例子,到目前为止我提出的代码都是编译和执行的,但它似乎认为数据中的每一行都是唯一的。 实际上在测试数据中有13行,只有6行是唯一的。 显然我做错了什么。
编辑 :我想我应该注意,有重复的行应该被删除,而不仅仅是该行的重复。 例如,如果有4个重复项,则应删除所有4个而不是3个,从4中留下一个唯一的行。
EDIT2 :或者,如果我可以选择所有重复的行(而不是尝试选择唯一的行),那对我来说没问题。 无论哪种方式都可以让我得到我的最终结果。
处理方法中的代码:
MyRowComparer myrc = new MyRowComparer(); var uniquerows = dtCSV.AsEnumerable().Distinct(myrc);
以及以下内容:
public class MyRowComparer : IEqualityComparer { public bool Equals(DataRow x, DataRow y) { //return ((string.Compare(x.Field("PRODUCT_ID"), y.Field("PRODUCT_ID"), true)) == // (string.Compare(x.Field("OWNER_ORG_ID"), y.Field("OWNER_ORG_ID"), true))); return x.ItemArray.Except(new object[] { x[x.Table.Columns["PRODUCT_ID"].ColumnName] }) == y.ItemArray.Except(new object[] { y[y.Table.Columns["PRODUCT_ID"].ColumnName] }) && x.ItemArray.Except(new object[] { x[x.Table.Columns["OWNER_ORG_ID"].ColumnName] }) == y.ItemArray.Except(new object[] { y[y.Table.Columns["OWNER_ORG_ID"].ColumnName] }); } public int GetHashCode(DataRow obj) { int y = int.Parse(obj.Field("PRODUCT_ID")); int z = int.Parse(obj.Field("OWNER_ORG_ID")); int c = y ^ z; return c; } }
您可以使用LINQ-To-DataSet和Enumerable.Except
/ Intersect
:
var tbl1ID = tbl1.AsEnumerable() .Select(r => new { product_id = r.Field("product_id"), owner_org_id = r.Field ("owner_org_id"), }); var tbl2ID = tbl2.AsEnumerable() .Select(r => new { product_id = r.Field ("product_id"), owner_org_id = r.Field ("owner_org_id"), }); var unique = tbl1ID.Except(tbl2ID); var both = tbl1ID.Intersect(tbl2ID); var tblUnique = (from uniqueRow in unique join row in tbl1.AsEnumerable() on uniqueRow equals new { product_id = row.Field ("product_id"), owner_org_id = row.Field ("owner_org_id") } select row).CopyToDataTable(); var tblBoth = (from bothRow in both join row in tbl1.AsEnumerable() on bothRow equals new { product_id = row.Field ("product_id"), owner_org_id = row.Field ("owner_org_id") } select row).CopyToDataTable();
编辑 :显然我已经误解了你的要求了一点点。 因此,您只有一个DataTable
并希望获得所有唯一且所有重复的行,这更加直截了当。 您可以将Enumerable.GroupBy
与包含两个字段的匿名类型一起使用:
var groups = tbl1.AsEnumerable() .GroupBy(r => new { product_id = r.Field("product_id"), owner_org_id = r.Field ("owner_org_id") }); var tblUniques = groups .Where(grp => grp.Count() == 1) .Select(grp => grp.Single()) .CopyToDataTable(); var tblDuplicates = groups .Where(grp => grp.Count() > 1) .SelectMany(grp => grp) .CopyToDataTable();
你的标准是关闭的。 您正在比较您不感兴趣的对象集( Except
排除)。
相反,尽可能清楚(数据类型)并保持简单:
public bool Equals(DataRow x, DataRow y) { // Usually you are dealing with INT keys return (x["PRODUCT_ID"] as int?) == (y["PRODUCT_ID"] as int?) && (x["OWNER_ORG_ID"] as int?) == (y["OWNER_ORG_ID"] as int?); // If you really are dealing with strings, this is the equivalent: // return (x["PRODUCT_ID"] as string) == (y["PRODUCT_ID"] as string) // && (x["OWNER_ORG_ID"] as string) == (y["OWNER_ORG_ID"] as string) }
如果可能,请检查null
。 也许您想要排除相同的行,因为它们的ID为null。
观察int?
。 这不是拼写错误。 如果要处理来自可以为NULL
列的数据库值,则需要问号。 原因是NULL
值将由C#中的DBNull
类型表示。 在这种情况下使用as
运算符只会给你null
(而不是InvalidCastException
。如果你确定,你正在处理INT NOT NULL
,使用(int)
进行InvalidCastException
。
字符串也是如此。 (string)
断言您期望非空DB值。
EDIT1:
这个类型错了。 ItemArray不是哈希表。 直接使用该行。
EDIT2:
添加了string
示例,一些评论
有关更直接的方法,请查看如何选择数据表中的不同行并存储到数组中
EDIT3:
关于演员的一些解释。
我建议的另一个链接与您的代码相同。 我忘记了你原来的意图;-)我刚看到你的代码并回答了最明显的错误,我看到了 – 抱歉
这是我如何解决问题
using System.Linq; using System.Data.Linq; var q = dtCSV .AsEnumerable() .GroupBy(r => new { ProductId = (int)r["PRODUCT_ID"], OwnerOrgId = (int)r["OWNER_ORG_ID"] }) .Where(g => g.Count() > 1).SelectMany(g => g); var duplicateRows = q.ToList();
我不知道这100%是否正确,我手头没有IDE。 而且你需要将演员阵容调整到合适的类型。 见上面我的补充。