我有两个表,如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
这里我想比较这两个表。如果DTTable1记录存在于DTTable2中(仅考虑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 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();
但有时候,第二行不会从表中删除。我得到了最终的DataTable
ItemID Specification Amount
--------- --------------- ---------
1 B 20
2 A 10
2 B 20
3 A 10
3 B 20
如何解决这个问题?这样做最简单的方法是什么?
答案 0 :(得分: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));
您的第二个示例失败,因为一旦删除了一行,后续行的索引会发生变化,但您会继续增加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()))
答案 1 :(得分:4)
尝试使用:
var list = DTTable2.Rows.ToList();//create new list of rows
foreach (DataRow DR in list)
{
//if bla bla bla
DTTable2.Rows.Remove(DR);
}
答案 2 :(得分: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();
答案 3 :(得分:0)
好,伙计们。我的处境几乎是相同的,无论我如何尝试,都不断遇到问题。我的解决方案是根本不尝试遍历DataTable。我从第一个DataTable中创建了一个数组(其中包含需要从第二个DataTable中删除的行)。遍历数组,并使用 select 删除与DataTable匹配的行。由于它不是循环,并且可以匹配DataTable中的任何行,所以我不再出错。
注意:原始数据表是一个1列的表,其中包含您要逐行从第二个数据表中删除的内容(无论它有多少列都没有关系)。用您的1列表的列名称替换“ LinkName =”。
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中找到的值不匹配。