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

时间:2014-03-29 10:37:40

标签: c#

我制作了一个方法,可以消除List中相同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++;
        }
    }

我该如何修复方法?谢谢你的帮助

2 个答案:

答案 0 :(得分:6)

首先,正如评论中所述,LINQ已经为您介绍了这一点:

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

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

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

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

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

  

只要集合保持不变,枚举器仍然有效。如果对集合进行了更改,例如添加,修改或删除元素,则枚举数将无法恢复,并且其行为未定义。

你可以通过迭代 index 而不是使用foreach循环来解决这个问题,但如果你要删除一个项目,你需要记住下面的所有内容都会向上移动一个元件。因此,您需要迭代向后来删除项目,或者您需要记住减少索引。

这是一种根据我们正在查看的内容使用索引转发进行迭代的方法,但是在寻找重复项时使用向后 - 当我们到达时停止我们正在关注的指数。请注意,这仍然是O(N 2 ) - 它不如使用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 post on it。)

答案 1 :(得分:1)

正如许多人所指出的,您可以使用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);
    }
}

如果你真的想创建一个&#34;删除重复项&#34;方法我会以这种方式(伪代码)完成它:

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),因此即使是大型列表也相当快。