如何在 C# 中迭代​​可枚举集合时修改或删除其中的项目

发布于 2024-07-09 03:16:23 字数 156 浏览 7 评论 0原文

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

I have to delete some rows from a data table. I've heard that it is not ok to change a collection while iterating through it. So instead of a for loop in which I check if a row meets the demands for deletion and then mark it as deleted, I should first iterate through the data table and add all of the rows in a list, then iterate through the list and mark the rows for deletions. What are the reasons for this, and what alternatives do I have (instead of using the rows list I mean)?.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

时光暖心i 2024-07-16 03:16:23

向后迭代列表听起来是一种更好的方法,因为如果您删除一个元素并且其他元素“落入间隙”,那并不重要,因为您已经查看过这些元素。 另外,您不必担心计数器变量会大于 .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);
            }
        }

Iterating Backwards through the List sounds like a better approach, because if you remove an element and other elements "fall into the gap", that does not matter because you have already looked at those. Also, you do not have to worry about your counter variable becoming larger than the .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);
            }
        }
雪落纷纷 2024-07-16 03:16:23

采用@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);

Taking @bruno code, I'd do it backwards.

Because when you move backwards, the missing array indices do not interfere with the order of your loop.

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

But seriuosly, these days, I'd use LINQ:

var l = new List<int>(new int[] { 0, 1, 2, 3, 4, 5, 6 });

l.RemoveAll(n => n % 2 == 0);
汐鸠 2024-07-16 03:16:23

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

You can remove elements from a collection if you use a simple for loop.

Take a look at this example:

        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);
        }
别闹i 2024-07-16 03:16:23

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

在行上调用删除将更改其 RowState属性设置为已删除,但将已删除的行保留在表中。 如果您在将更改保存回服务器之前仍然需要使用此表(例如,如果您想显示表的内容减去已删除的行),则需要在像这样迭代时检查每行的 RowState :

foreach (DataRow row in dt.Rows)
{
    if (row.RowState != DataRowState.Deleted)
    {
        // this row has not been deleted - go ahead and show it
    }
}

从集合中删除行(如布鲁诺的回答)将破坏表适配器,通常不应使用数据表来完成。

Since you're working with a DataTable and need to be able to persist any changes back to the server with a table adapter (see comments), here is an example of how you should delete rows:

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

Calling delete on the rows will change their RowState property to Deleted, but leave the deleted rows in the table. If you still need to work with this table before persisting changes back to the server (like if you want to display the table's contents minus the deleted rows), you need to check the RowState of each row as you're iterating through it like this:

foreach (DataRow row in dt.Rows)
{
    if (row.RowState != DataRowState.Deleted)
    {
        // this row has not been deleted - go ahead and show it
    }
}

Removing rows from the collection (as in bruno's answer) will break the table adapter, and should generally not be done with a DataTable.

你在看孤独的风景 2024-07-16 03:16:23

while 循环可以处理这个问题:

int i = 0;
while(i < list.Count)
{
    if(<codition for removing element met>)
    {
        list.RemoveAt(i);
    }
    else
    {
        i++;
    }
}

A while loop would handle this:

int i = 0;
while(i < list.Count)
{
    if(<codition for removing element met>)
    {
        list.RemoveAt(i);
    }
    else
    {
        i++;
    }
}
作业与我同在 2024-07-16 03:16:23

如果您通过使用委托而不是 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));
}

chakrit's solution can also be used if you are targetting .NET 2.0 (no LINQ/lambda expressions) by using a delegate rather than a lambda expression:

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));
}
忘羡 2024-07-16 03:16:23

正如您所说,在迭代列表时删除或添加到列表可能会破坏它。

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

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.

Deleting or adding to the list whilst iterating through it can break it, like you said.

I often used a two list approach to solve the problem:

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.
生来就爱笑 2024-07-16 03:16:23

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

When I need to remove an item from a collection that I am enumerating I usually enumerate it in reverse.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文