确定数据表中的重复项

我有一个从CSV文件加载的数据表。 我需要根据数据表中的两列( product_idowner_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。 而且你需要将演员阵容调整到合适的类型。 见上面我的补充。