简体   繁体   English

使用C#比较和删除数据表行:

[英]Compare and delete datatable row using C#:

I have two tables such as DTTable1 and DTTable2. 我有两个表,如DTTable1和DTTable2。 It has the following records. 它有以下记录。

DTTable1: DTTable1:

    ItemID     Specification    Amount
   ---------  ---------------  ---------
      1             A             10
      1             B             20
      1             C             30

DTTable1: DTTable1:

    ItemID     Specification    Amount
   ---------  ---------------  ---------
      1             A             10
      1             B             20
      1             C             30
      2             A             10
      2             B             20
      3             A             10
      3             B             20

Here I want to compare these two tables. 在这里,我想比较这两个表。 If DTTable1 records present in DTTable2(consider only ItemID) then remove the corresponding rows which has the ItemID same as DTTable1. 如果DTTable1记录存在于DTTable2中(仅考虑ItemID),则删除ItemID与DTTable1相同的相应行。

I have tried foreach and forloop. 我试过foreach和forloop。 Using ForEach: 使用ForEach:

   foreach (DataRow DR in DTTable2.Rows)
   {
      if (DR["ItemID"].ToString() == DTTable1.Rows[0]["ItemID"].ToString())
      {
           DTTable2.Rows.Remove(DR);                            
      }
   }
   DTTable2.AcceptChanges();

It showed the error, "Collection was modified; enumeration operation might not execute". 它显示错误,“集合已被修改;枚举操作可能无法执行”。 So I used For Loop, It also not given the desired result. 所以我使用For Loop,它也没有给出所需的结果。

Using For Loop: 使用For循环:

   for (int i = 0; i < DTTable2.Rows.Count; i++)
   {
       if (DTTable2.Rows[i]["ItemID"].ToString() == DTTable1.Rows[0]["ItemID"].ToString())
       {
           DTTable2.Rows.RemoveAt(i);
       }
   }
   DTTable2.AcceptChanges();

But sometimes, the second row doesn't remove from the table. 但有时,第二行不会从表中删除。 I get the final DataTable as 我得到了最终的DataTable

    ItemID     Specification    Amount
   ---------  ---------------  ---------
      1             B             20
      2             A             10
      2             B             20
      3             A             10
      3             B             20

How to solve this? 怎么解决这个? What is the simplest method to do this? 这样做最简单的方法是什么?

You can't modify a collection while you are enumerating it as in your first example. 在第一个示例中枚举时,无法修改集合。 You should instead get a list of the rows to delete and then delete them. 您应该获取要删除的行的列表,然后删除它们。

List<DataRow> rowsToDelete = new List<DataRow>();
foreach (DataRow DR in DTTable2.Rows)
{
    if (DR["ItemID"].ToString() == DTTable1.Rows[0]["ItemID"].ToString())
        rowsToDelete.Add(DR);           
}

foreach (var r in rowsToDelete)
    DTTable2.Rows.Remove(r);

Or, inline using linq: 或者,使用linq内联:

DTTable2.Rows
    .Where(DR => DR["ItemID"].ToString() == DTTable1.Rows[0]["ItemID"].ToString())
    .ToList()
    .ForEach(r => DTTable2.Rows.Remove(r));

Your second example fails because once a row is removed, the indexes of subsequent rows change but you continue to increment i , which effectively skips over the row immediately following the deleted row. 您的第二个示例失败,因为一旦删除了一行,后续行的索引会发生变化,但您会继续增加i ,这会有效地跳过已删除行之后的行。 There are two ways around this: 有两种方法:

for (int i = DTTable2.Rows.Count - 1; i >= 0; i--)
    if (DTTable2.Rows[i]["ItemID"].ToString() == DTTable1.Rows[0]["ItemID"].ToString())
        DTTable2.Rows.RemoveAt(i);

Or 要么

int i = 0;
while (i < DTTable2.Rows.Count)
{
    if (DTTable2.Rows[i]["ItemID"].ToString() == DTTable1.Rows[0]["ItemID"].ToString())
        DTTable2.Rows.RemoveAt(i);
    else
        i++;
}

Side note: I wonder if you really mean to always compare to row 0's data, given your description. 旁注:我想知道你是否真的想要总是比较第0行的数据,给出你的描述。 Perhaps you meant to compare all rows like the following instead (although not optimal at all)? 也许你的意思是比较下面的所有行(尽管不是最优的)?

if (DTTable1.Any(r => DTTable2.Rows[i]["ItemID"].ToString() == r["ItemID"].ToString()))

Try to use: 尝试使用:

var list = DTTable2.Rows.ToList();//create new list of rows
foreach (DataRow DR in list)
{
    //if bla bla bla
    DTTable2.Rows.Remove(DR);
}

You can use LINQ to DataTable : 您可以使用LINQ to DataTable

var result =  DTTable1.AsEnumerable()
                   .Where(row => !DTTable2.AsEnumerable()
                                         .Select(r => r.Field<int>("ItemID"))
                                         .Any(x => x == row.Field<int>("ItemID"))
                  ).CopyToDataTable();

Well, guys. 好吧,伙计们。 I had an almost identical situation and no matter how I tried to do it, I kept running into problems. 我有一个几乎相同的情况,无论我怎么做,我一直遇到问题。 My solution was not to try and loop through the DataTable at all. 我的解决方案是不要尝试遍历DataTable。 I made an array from the first DataTable (this contained the rows that needed to be deleted from the second DataTable). 我从第一个DataTable创建了一个数组(这包含需要从第二个DataTable中删除的行)。 Loop through the Array and use a select to remove the row that matched in the DataTable. 循环遍历数组并使用select删除DataTable中匹配的行。 Since it wasn't a loop, and it could match any row in the DataTable, I quit getting errors. 因为它不是一个循环,并且它可以匹配DataTable中的任何行,所以我放弃了获取错误。

Note: Original DataTable is a 1-column table that contains what you are trying to remove from the second DataTable by row (doesn't matter how many columns it has). 注意:原始DataTable是一个1列的表,其中包含您尝试从第二个DataTable中删除的内容(与它有多少列无关)。 Replace "LinkName=' w/ the column name for your 1-column table. 将“LinkName ='w替换为1列表的列名称。

 public DataTable RemoveDuplicateRows(DataTable OriginalLinks, DataTable UpdatedLinks) // OriginalLinks is a 1-col dt to delete from new dt
    {

        ArrayList arrOriginalLinks = new ArrayList();

        if (OriginalLinks.Rows.Count > 0)
        {

            foreach (DataRow dr in OriginalLinks.Rows)
            {
                arrOriginalLinks.Add(dr["LinkName"]);
            }
        }


        if (OriginalLinks.Rows.Count == 0)
        {
            // do nothing
        }
        else
        {
            for (int i = OriginalLinks.Rows.Count - 1; i >= 0; i--)
            {
                string filter = "LinkName='" + arrOriginalLinks[i].ToString() + "'";

                UpdatedLinks.Select(filter).ToList().ForEach(r => r.Delete());


            }

        }

        return UpdatedLinks;

    }

This returns the second DataTable with just the rows left that didn't match a value found in the first DataTable. 这将返回第二个DataTable,其中只剩下与第一个DataTable中找到的值不匹配的行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM