我必须从数据表中删除一些行。我听说在迭代它时改变一个集合是不行的。因此,我不是检查一行是否满足删除要求然后将其标记为已删除的for循环,而应首先遍历数据表并在列表中添加所有行,然后遍历列表并标记删除行。这是什么原因,我有什么替代方案(而不是使用我的意思的行列表)?。

有帮助吗?

解决方案

如果使用简单的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);
        }

其他提示

向后遍历列表听起来像是一种更好的方法,因为如果你删除一个元素和其他元素<!>“落入间隙<!>”,那没关系,因为你已经看过那些了。此外,您不必担心您的计数器变量会变得大于.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);

由于您正在使用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
    }
}

从集合中删除行(如bruno的答案)将破坏表适配器,通常不应该使用DataTable。

while循环可以解决这个问题:

int i = 0;
while(i < list.Count)
{
    if(<codition for removing element met>)
    {
        list.RemoveAt(i);
    }
    else
    {
        i++;
    }
}
如果您使用委托而不是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));
}

在迭代过程中删除或添加列表可以打破它,就像你说的那样。

我经常使用两个列表的方法来解决问题:

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.

当我需要从我正在枚举的集合中删除一个项目时,我通常会反过来枚举它。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top