从列表的 foreach 循环中的列表中删除对象

本文关键字:列表 删除 对象 foreach 循环 | 更新日期: 2023-09-27 17:55:15

我制作了一种消除列表中相同string的任何重复的方法。

现在,问题是它给了我这个错误:

System.InvalidOperationException: Collection was modified; enumeration operation may not execute.

我在互联网上阅读,我认为问题是我正在从列表foreach循环内的列表中删除一个对象。

    foreach (string r in list)
    {
        int numberOfAppearance=0;
        foreach (string rs in list)
        {
            if (r == rs && numberOfAppearance> 0)
                list.Remove(rs);
            else
                numberOfAppearance++;
        }
    }

如何修复该方法?感谢您的帮助

从列表的 foreach 循环中的列表中删除对象

首先,如注释中所述,LINQ 已在此处为您提供了介绍:

list = list.Distinct().ToList();
非常

值得研究 LINQ 的数据操作 - 它可以使事情变得更加简单。

至于您当前的代码出了什么问题 - 有几件事:

首先,您按

项目而不是按索引删除,这将删除该项目的第一次出现,而不是您实际查看

的项目

其次,如果您在迭代列表时对其进行修改,您将获得您所看到的异常。来自List<T>.GetEnumerator的文档:

只要集合保持不变,枚举器就保持有效。如果对集合进行了更改(如添加、修改或删除元素),则枚举器将不可恢复地失效,并且其行为未定义。

您可以通过按索引迭代而不是使用 foreach 循环来解决此问题,但是如果您要删除一个项目,则需要记住,下面的所有内容都将向上移动一个元素。因此,要么需要向后迭代以删除项目,要么需要记住递减索引。

这是一种方法,它根据我们正在查看的内容使用索引向前迭代,但在查找重复项方面向迭代 - 当我们到达我们正在查看的索引时停止。请注意,这仍然是 O(N2) - 它不如使用 Distinct 有效:

// We're looking for duplicates *after* list[i], so we don't need to go as far
// as i being the very last element: there aren't any elements after it to be
// duplicates. (We could easily still just use list.Count, and the loop for j
// would just have 0 iterations.)
for (int i = 0; i < list.Count - 1; i++)
{
    // Go backwards from the end, looking for duplicates of list[i]
    for (int j = list.Count - 1; j > i; j--)
    {
        if (list[j] == list[i])
        {
            list.RemoveAt(j);
        }
    }
}

(有关Distinct的更多详细信息,请参阅我的Edulinq帖子。

正如许多人指出的那样,您可以使用Distinct方法来解决您的特定问题。

但是,您

实际遇到的问题是,当您迭代列表时,您正在尝试修改列表,这不会有好结果。

//This will not work.
foreach (string rs in list)
{
    if (some_test)
    {
        list.Remove(rs); //Because of this line.
    }
}

如果你想做类似的事情,你需要找到解决这个问题的方法。通常它涉及创建一个新数组。

对于此考试,您可以执行以下操作

List newList = new ArrayList();
foreach (string rs in list)
{
    if (!some_test)
    {
        newList.add(rs);
    }
}

如果你真的想创建一个"删除重复项"的方法,我会以这种方式(伪代码)来完成:

Hash cache_hash = new Hash(default false)
List new_list = new List
foreach string s in list
{
    if not cache_hash[s]
    {
        new_list.add(s)
        cache_hash[s] = true
    }
}
list = new_list

这种方法是Ω(N)的,所以它即使在大型列表中也相当快。