4

DTTable1 と DTTable2 などの 2 つのテーブルがあります。以下の記録があります。

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

ここで、これら 2 つの表を比較したいと思います。DTTable1 レコードが DTTable2 に存在する場合 (ItemID のみを考慮)、DTTable1 と同じ ItemID を持つ対応する行を削除します。

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

ただし、2 番目の行がテーブルから削除されない場合があります。最終的な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));

行が削除されると、後続の行のインデックスは変更されますが、増加し続けるため、2 番目の例は失敗しますi。これにより、削除された行の直後の行が事実上スキップされます。これには 2 つの方法があります。

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 に答える