【发布时间】:2010-09-23 10:26:24
【问题描述】:
我必须从数据表中删除一些行。我听说在迭代集合时更改集合是不行的。因此,我应该首先遍历数据表并将所有行添加到列表中,然后遍历列表并标记删除的行。这是什么原因,我有什么替代方案(而不是使用我的意思的行列表)?
【问题讨论】:
-
我编辑了标题以便更容易找到这个问题。我之前关闭了一个骗局,但我可以看到用户可能错过了这个带有旧标题的问题。
标签: c# collections iteration
我必须从数据表中删除一些行。我听说在迭代集合时更改集合是不行的。因此,我应该首先遍历数据表并将所有行添加到列表中,然后遍历列表并标记删除的行。这是什么原因,我有什么替代方案(而不是使用我的意思的行列表)?
【问题讨论】:
标签: c# collections iteration
如果您通过使用委托而不是 lambda 表达式来定位 .NET 2.0(无 LINQ/lambda 表达式),也可以使用 chakrit 的解决方案:
public bool IsMatch(int item) {
return (item % 3 == 1); // put whatever condition you want here
}
public void RemoveMatching() {
List<int> x = new List<int>();
x.RemoveAll(new Predicate<int>(IsMatch));
}
【讨论】:
使用@bruno 代码,我会倒着做。
因为向后移动时,缺少的数组索引不会干扰循环的顺序。
var l = new List<int>(new int[] { 0, 1, 2, 3, 4, 5, 6 });
for (int i = l.Count - 1; i >= 0; i--)
if (l[i] % 2 == 0)
l.RemoveAt(i);
foreach (var i in l)
{
Console.WriteLine(i);
}
但是说真的,这些天,我会使用 LINQ:
var l = new List<int>(new int[] { 0, 1, 2, 3, 4, 5, 6 });
l.RemoveAll(n => n % 2 == 0);
【讨论】:
当我需要从我正在枚举的集合中删除一个项目时,我通常会反向枚举它。
【讨论】:
通过列表向后迭代听起来是一种更好的方法,因为如果您删除一个元素而其他元素“落入间隙”,那并不重要,因为您已经看过这些了。此外,您不必担心您的计数器变量会变得大于 .Count。
List<int> test = new List<int>();
test.Add(1);
test.Add(2);
test.Add(3);
test.Add(4);
test.Add(5);
test.Add(6);
test.Add(7);
test.Add(8);
for (int i = test.Count-1; i > -1; i--)
{
if(someCondition){
test.RemoveAt(i);
}
}
【讨论】:
由于您正在使用 DataTable,并且需要能够使用表适配器将任何更改持久化回服务器(请参阅 cmets),以下是您应该如何删除行的示例:
DataTable dt;
// remove all rows where the last name starts with "B"
foreach (DataRow row in dt.Rows)
{
if (row["LASTNAME"].ToString().StartsWith("B"))
{
// mark the row for deletion:
row.Delete();
}
}
对行调用 delete 会将其 RowState 属性更改为 Deleted,但将删除的行保留在表中。如果在将更改持久化回服务器之前仍需要使用此表(例如,如果您想显示表的内容减去已删除的行),则需要在迭代时检查每一行的 RowState 像这样:
foreach (DataRow row in dt.Rows)
{
if (row.RowState != DataRowState.Deleted)
{
// this row has not been deleted - go ahead and show it
}
}
从集合中删除行(如 bruno 的回答)会破坏表适配器,通常不应使用 DataTable 来完成。
【讨论】:
如您所说,在迭代列表时删除或添加列表可能会破坏它。
我经常使用两个列表的方法来解决问题:
ArrayList matches = new ArrayList(); //second list
for MyObject obj in my_list
{
if (obj.property == value_i_care_about)
matches.addLast(obj);
}
//now modify
for MyObject m in matches
{
my_list.remove(m); //use second list to delete from first list
}
//finished.
【讨论】:
如果您使用简单的for 循环,则可以从集合中删除元素。
看看这个例子:
var l = new List<int>();
l.Add(0);
l.Add(1);
l.Add(2);
l.Add(3);
l.Add(4);
l.Add(5);
l.Add(6);
for (int i = 0; i < l.Count; i++)
{
if (l[i] % 2 == 0)
{
l.RemoveAt(i);
i--;
}
}
foreach (var i in l)
{
Console.WriteLine(i);
}
【讨论】:
while 循环会处理这个问题:
int i = 0;
while(i < list.Count)
{
if(<codition for removing element met>)
{
list.RemoveAt(i);
}
else
{
i++;
}
}
【讨论】: