C# 确定数据表中的重复项

C# 确定数据表中的重复项,c#,datatable,duplicates,C#,Datatable,Duplicates,我有一个从CSV文件加载的数据表。我需要根据数据表中的两列(product\u id和owner\u org\u id)确定哪些行是重复的。一旦确定了这一点,我就可以使用这些信息来构建结果,这是一个只包含非唯一行的数据表,以及一个只包含唯一行的数据表 我已经看过了这里的其他示例,到目前为止,我所提供的代码是编译和执行的,但它似乎认为数据中的每一行都是唯一的。实际上,在测试数据中有13行,只有6行是唯一的。很明显我做错了什么 编辑:我想我应该注意,应该删除所有重复的行,而不仅仅是该行的重复行。例如

我有一个从CSV文件加载的数据表。我需要根据数据表中的两列(
product\u id
owner\u org\u id
)确定哪些行是重复的。一旦确定了这一点,我就可以使用这些信息来构建结果,这是一个只包含非唯一行的数据表,以及一个只包含唯一行的数据表

我已经看过了这里的其他示例,到目前为止,我所提供的代码是编译和执行的,但它似乎认为数据中的每一行都是唯一的。实际上,在测试数据中有13行,只有6行是唯一的。很明显我做错了什么

编辑:我想我应该注意,应该删除所有重复的行,而不仅仅是该行的重复行。例如,如果有4个重复项,则应删除所有4个,而不是3个,从4个重复项中保留一个唯一的行

EDIT2:或者,如果我可以选择所有重复的行(而不是尝试选择唯一的行),我也可以。任何一种方法都能让我达到我的最终结果

处理方法中的代码:

MyRowComparer myrc = new MyRowComparer();
var uniquerows = dtCSV.AsEnumerable().Distinct(myrc);
连同以下各项:

public class MyRowComparer : IEqualityComparer<DataRow>
{
    public bool Equals(DataRow x, DataRow y)
    {
        //return ((string.Compare(x.Field<string>("PRODUCT_ID"),   y.Field<string>("PRODUCT_ID"),   true)) ==
        //        (string.Compare(x.Field<string>("OWNER_ORG_ID"), y.Field<string>("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<string>("PRODUCT_ID"));
        int z = int.Parse(obj.Field<string>("OWNER_ORG_ID"));
        int c = y ^ z;
        return c;
    }
}
公共类MyRowComparer:IEqualityComparer
{
公共布尔等于(数据行x、数据行y)
{
//返回((string.Compare(x.Field(“产品标识”),y.Field(“产品标识”),true))==
//(string.Compare(x.Field(“OWNER\u ORG\u ID”)、y.Field(“OWNER\u ORG\u ID”)、true);
返回
x、 ItemArray.Exception(新对象[]{x[x.Table.Columns[“PRODUCT_ID”].ColumnName]})==
y、 ItemArray.Exception(新对象[]{y[y.Table.Columns[“PRODUCT_ID”].ColumnName]})&&
x、 ItemArray.Exception(新对象[]{x[x.Table.Columns[“OWNER\u ORG\u ID”].ColumnName]})==
y、 ItemArray.Except(新对象[]{y[y.Table.Columns[“OWNER\u ORG\u ID”].ColumnName]});
}
public int GetHashCode(DataRow obj)
{
int y=int.Parse(对象字段(“产品标识”);
intz=int.Parse(对象字段(“所有者组织ID”);
int c=y^z;
返回c;
}
}

您的准则已关闭。您正在比较您不感兴趣的对象集(
除外
排除)

相反,应尽可能清楚(数据类型),并保持简单:

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)
强制转换

字符串也是如此。
(string)
断言您期望的是非空DB值

编辑1:

类型错误。ItemArray不是哈希表。请直接使用该行

编辑2:

添加了
string
示例,一些注释

要获得更直接的方法,请检查

编辑3:

关于演员阵容的一些解释

我建议的另一个链接与您的代码相同。我忘记了您的初衷;-)我刚刚看到了您的代码,并对最明显的错误作出了响应,我看到了-抱歉

下面是我将如何解决这个问题

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。您需要将类型转换调整为适当的类型。请参阅我上面的添加内容。

您的标准已关闭。您正在比较您不感兴趣的对象集(
除外
排除)

相反,应尽可能清楚(数据类型),并保持简单:

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)
强制转换

字符串也是如此。
(string)
断言您期望的是非空DB值

编辑1:

类型错误。ItemArray不是哈希表。请直接使用该行

编辑2:

添加了
string
示例,一些注释

要获得更直接的方法,请检查

编辑3:

关于演员阵容的一些解释

我建议的另一个链接与您的代码相同。我忘记了您的初衷;-)我刚刚看到了您的代码,并对最明显的错误作出了响应,我看到了-抱歉

下面是我将如何解决这个问题

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。您需要将类型转换调整为适当的类型。请参阅上面我的添加。

您可以使用LINQ来创建数据集和可枚举。除了/
相交

var tbl1ID = tbl1.AsEnumerable()
        .Select(r => new
        {
            product_id = r.Field<String>("product_id"),
            owner_org_id = r.Field<String>("owner_org_id"),
        });
var tbl2ID = tbl2.AsEnumerable()
        .Select(r => new
        {
            product_id = r.Field<String>("product_id"),
            owner_org_id = r.Field<String>("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<String>("product_id"),
                    owner_org_id = row.Field<String>("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<String>("product_id"),
                  owner_org_id = row.Field<String>("owner_org_id")
              }
              select row).CopyToDataTable();

您可以使用LINQ来创建数据集和可枚举。除了/
相交

var tbl1ID = tbl1.AsEnumerable()
        .Select(r => new
        {
            product_id = r.Field<String>("product_id"),
            owner_org_id = r.Field<String>("owner_org_id"),
        });
var tbl2ID = tbl2.AsEnumerable()
        .Select(r => new
        {
            product_id = r.Field<String>("product_id"),
            owner_org_id = r.Field<String>("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<String>("product_id"),
                    owner_org_id = row.Field<String>("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<String>("product_id"),
                  owner_org_id = row.Field<String>("owner_org_id")
              }
              select row).CopyToDataTable();

我不明白您为什么要使用
,除了
——为什么不只是比较两个重要列的值?另外
x.Table.Columns[“PRODUCT_ID”]。ColumnName
在定义上应该与“PRODUCT_ID”相同,因此您可以跳过列查找。我不明白您为什么要使用
,除了
-为什么您不只是比较两个重要列的值?另外
x.Table.Columns[“PRODUCT_ID”]。ColumnName
在定义上应与“PRODUCT_ID”相同,