比较2个数据表,找出列之间的差异/准确性



所以,我有两个独立的数据表,看起来非常相同,但在他们的行值可能是不同的,例如。

编辑:

我可以有一个唯一的ID通过创建一个临时标识列,可以用作主键,如果这将使它更容易。所以把ID列当作主键。

ID |  Name | Value1 | Value2 | Value3
-------------------------------------
1  |  Bob  |   50   |  150   |  35
2  |  Bill |   55   |  47    |  98
3  |  Pat  |   10   |  15    |  45
4  |  Cat  |   70   |  150   |  35
表B

ID |  Name | Value1 | Value2 | Value3
-------------------------------------
1  |  Bob  |   30   |  34    |  67
2  |  Bill |   55   |  47    |  98
3  |  Pat  |   100  |  15    |  45
4  |  Cat  |   70   |  100   |  20

输出应该是:

表C

ID |  Name | TableAValue1 | TableBValue1 | DiffValue1 ....Samething for Value2 .....samething for value3
------------------------------------------------------
1  |  Bob  |   50         |   30         |    20          
2  |  Bill |   55         |   55         |    0               
3  |  Pat  |   10         |   100        |    90                
4  |  Cat  |   70         |   70         |    0                    

我知道这样做的繁琐方法是通过使用forloop并循环遍历每一行并相互比较列行。但我不确定如何创建一个新的表C与我想要的结果。此外,我认为使用Linq可能有一个更简单的解决方案,我不是很熟悉,但我会对linq的解决方案感兴趣,如果它更快,更少的代码行。我正在寻找最优/最有效的方式去做这件事。因为这些数据表的大小可以在5000到15000行之间,所以内存使用成为一个问题

LINQ不是更快,至少不是一般。但它可以帮助提高可读性。

你可以使用Enumerable.Join,这可能比嵌套循环更有效,但你需要一个循环来填充你的第三个表。所以前两列是标识符,其余的是值:

var query = from r1 in table1.AsEnumerable()
            join r2 in table2.AsEnumerable()
            on new { ID = r1.Field<int>("ID"), Name = r1.Field<string>("Name") }
            equals new { ID = r2.Field<int>("ID"), Name = r2.Field<string>("Name") }
            select new { r1, r2 };
var columnsToCompare = table1.Columns.Cast<DataColumn>().Skip(2);
foreach (var rowInfo in query)
{
    var row = table3.Rows.Add();
    row.SetField("ID", rowInfo.r1.Field<int>("ID"));
    row.SetField("Name", rowInfo.r1.Field<int>("Name"));
    foreach (DataColumn col in columnsToCompare)
    { 
        int val1 = rowInfo.r1.Field<int>(col.ColumnName);
        int val2 = rowInfo.r2.Field<int>(col.ColumnName);
        int diff = (int)Math.Abs(val1-val2);
        row.SetField(col.ColumnName, diff);
    }
}
var tableC = new DataTable();
tableC.Columns.Add(new DataColumn("ID"));
tableC.Columns.Add(new DataColumn("Name"));
tableC.Columns.Add(new DataColumn("TableAValue1"));
tableC.Columns.Add(new DataColumn("TableBValue1"));
tableC.Columns.Add(new DataColumn("DiffValue1"));
foreach (DataRow rowA in tableA.Rows)
{
    foreach (DataRow rowB in tableB.Rows)
    {
        if (Convert.ToInt32(rowA["ID"]) == Convert.ToInt32(rowB["ID"]) &&
            rowA["Name"].ToString() == rowB["Name"].ToString() &&
            Convert.ToInt32(rowA["Value1"]) != Convert.ToInt32(rowB["Value1"]))
        {
            var newRow = tableC.NewRow();
            newRow["ID"] = rowA["ID"];
            newRow["Name"] = rowA["Name"];
            newRow["TableAValue1"] = rowA["Value1"];
            newRow["TableBValue1"] = rowB["Value1"];
            newRow["DiffValue1"] = Convert.ToInt32(rowA["Value1"]) - Convert.ToInt32(rowB["Value1"]);
            tableC.Rows.Add(newRow);
        }
    }
}

使用LINQ创建一个匿名类型,如下所示

    var joinedRows = (from rowA in TableA.AsEnumerable()
                      from rowB in TableB.AsEnumerable()
                      where rowA.Field<String>("Name") == rowB.Field<String>("Name")
                      select new
                                 {
                                     ID = rowA.Field<int>("ID"),
                                     Name = rowA.Field<String>("Name"),
                                     TableAValue1 = rowA.Field<int>("Value1"),
                                     TableBValue1 = rowB.Field<int>("Value1"),
                                     DiffValue1 = Math.Abs(rowA.Field<int>("Value1") - rowB.Field<int>("Value1")),
                                     TableAValue2 = rowA.Field<int>("Value2"),
                                     TableBValue2 = rowB.Field<int>("Value2"),
                                     DiffValue2 = Math.Abs(rowA.Field<int>("Value2") - rowB.Field<int>("Value2")),
                                     TableAValue3 = rowA.Field<int>("Value3"),
                                     TableBValue3 = rowB.Field<int>("Value3"),
                                     DiffValue3 = Math.Abs(rowA.Field<int>("Value3") - rowB.Field<int>("Value3"))
                                 });

Table.AsEnumerable()将给你一个IEnumerable(of DataRow)行。字段将其强制转换为适合您的正确类型

您现在可以使用匿名类型joinedRows并从它创建新的数据表

这使用了类似于kippermand的策略,但是通过避免O(n²)检查每个ID与其他ID的复杂性,并通过重用从数据表中提取的值,在大型数据集上可能会执行得稍微好一些:

// joining by row location
var joinedTableRows =
    dt1.AsEnumerable().Zip(dt2.AsEnumerable(),
        (r1, r2) => new{r1, r2});
// or, joining by ID
var joinedTableRows2 =
    dt1.AsEnumerable().Join(dt2.AsEnumerable(),
        r => r.Field<int>("ID"),
        r => r.Field<int>("ID"),
        (r1, r2) => new{r1, r2});
var result =
    from row in joinedTableRows
    let rowA = row.r1
    let rowB = row.r2
    let tableAValue1 = rowA.Field<int>("Value1")
    let tableBValue1 = rowB.Field<int>("Value1")
    let tableAValue2 = rowA.Field<int>("Value2")
    let tableBValue2 = rowB.Field<int>("Value2")
    let tableAValue3 = rowA.Field<int>("Value3")
    let tableBValue3 = rowB.Field<int>("Value3")
    select new
    {
        ID = row.r1.Field<int>("ID"),
        Name = row.r1.Field<string>("Name"),
        TableAValue1 = tableAValue1,
        TableBValue1 = tableBValue1,
        DiffValue1 = Math.Abs(tableAValue1 - tableBValue1),
        TableAValue2 = tableAValue2,
        TableBValue2 = tableBValue2,
        DiffValue2 = Math.Abs(tableAValue2 - tableBValue2),
        TableAValue3 = tableAValue3,
        TableBValue3 = tableBValue3,
        DiffValue3 = Math.Abs(tableAValue3 - tableBValue3)
    };

根据您的数据需要如何被使用,您可以声明一个匹配此匿名类型的类,并直接使用它(这是我更喜欢的),或者您可以从这些对象创建一个DataTable,如果您必须的话。

相关内容

  • 没有找到相关文章

最新更新