4

我有两个表,例如 DTTable1 和 DTTable2。它有以下记录。

DTTable1:

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

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

在这里,我想比较这两个表。如果 DTTable2 中存在 DTTable1 记录(仅考虑 ItemID),则删除 ItemID 与 DTTable1 相同的相应行。

我试过foreach和forloop。使用 ForEach:

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

它显示错误,“集合已修改;枚举操作可能无法执行”。所以我使用了 For 循环,它也没有给出想要的结果。

使用 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();

但有时,第二行不会从表中删除。我得到最终的 DataTable 为

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

如何解决这个问题?最简单的方法是什么?

4

4 回答 4

6

枚举时不能修改集合,就像在第一个示例中一样。相反,您应该获取要删除的行列表,然后将其删除。

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);

或者,使用 linq 内联:

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

您的第二个示例失败,因为一旦删除了一行,后续行的索引就会更改,但您会继续 increment i,这实际上会跳过紧跟已删除行的行。有两种方法可以解决这个问题:

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);

或者

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++;
}

旁注:根据您的描述,我想知道您是否真的要始终与第 0 行的数据进行比较。也许您的意思是比较所有行,如下所示(尽管根本不是最佳的)?

if (DTTable1.Any(r => DTTable2.Rows[i]["ItemID"].ToString() == r["ItemID"].ToString()))
于 2012-10-10T05:36:27.720 回答
4

尝试使用:

var list = DTTable2.Rows.ToList();//create new list of rows
foreach (DataRow DR in list)
{
    //if bla bla bla
    DTTable2.Rows.Remove(DR);
}
于 2012-10-10T05:36:12.657 回答
4

您可以使用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();
于 2012-10-10T05:45:37.310 回答
0

好吧,伙计们。我的情况几乎相同,无论我如何尝试,我一直遇到问题。我的解决方案是根本不尝试遍历 DataTable。我从第一个 DataTable 中创建了一个数组(其中包含需要从第二个 DataTable 中删除的行)。遍历 Array 并使用select删除 DataTable 中匹配的行。由于它不是一个循环,并且它可以匹配 DataTable 中的任何行,所以我不再遇到错误。

注意:原始 DataTable 是一个 1 列表,其中包含您尝试按行从第二个 DataTable 中删除的内容(不管它有多少列)。将“LinkName=”替换为 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;

    }

这将返回第二个 DataTable,其中仅剩下与第一个 DataTable 中的值不匹配的行。

于 2018-09-18T02:53:18.933 回答