我需要从数据表中删除一些行。我听说在迭代过程中更改集合是不可取的。因此,我应该先遍历整个数据表并将所有行添加到列表中,然后遍历列表并标记要删除的行,而不是使用for循环来检查是否满足删除条件,然后标记为已删除。这样做的原因是什么?还有没有其他替代方法(而不是使用行列表)?
我需要从数据表中删除一些行。我听说在迭代过程中更改集合是不可取的。因此,我应该先遍历整个数据表并将所有行添加到列表中,然后遍历列表并标记要删除的行,而不是使用for循环来检查是否满足删除条件,然后标记为已删除。这样做的原因是什么?还有没有其他替代方法(而不是使用行列表)?
通过反向迭代列表听起来是更好的方法,因为如果你删除一个元素并且其他元素“填补了这个空隙”,那也没关系,因为你已经查看了那些元素。此外,您不必担心计数器变量变得大于.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);
}
}
借鉴 @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);
如果您使用简单的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);
}
如果您正在使用DataTable并需要能够通过表格适配器将任何更改持久化到服务器(请参见注释),这里是一个示例,说明您应该如何删除行:
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
}
}
从集合中删除行(就像布鲁诺的答案中所示)将会破坏表适配器,并且通常不应该在 DataTable 中这样做。
int i = 0;
while(i < list.Count)
{
if(<codition for removing element met>)
{
list.RemoveAt(i);
}
else
{
i++;
}
}
如果你的目标是.NET 2.0(没有LINQ/lambda表达式),那么可以使用chakrit的解决方案,通过使用委托而不是lambda表达式:
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));
}
在遍历列表时进行添加或删除操作可能会破坏它,就像你所说的那样。
我通常使用双列表方法来解决这个问题:
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.
当我需要从正在枚举的集合中移除一个项目时,我通常会反向枚举它。