13

复制

在迭代时修改集合


有没有人有一个很好的模式可以让我在循环遍历可枚举集合(例如,字典中的 IList 或 KeyValuePairs)时解决无法删除对象的问题

例如,以下失败,因为它修改了在 foreach 期间枚举的列表

foreach (MyObject myObject in MyListOfMyObjects)
{
     if (condition) MyListOfMyObjects.Remove(myObject);
}

过去我使用了两种方法。

我已将 foreach 替换为反向 for 循环(以免在删除对象时更改我正在循环的任何索引)。

我还尝试存储一个新的对象集合以在循环中删除,然后遍历该集合并从原始集合中删除对象。

这些工作正常,但都感觉不好,我想知道是否有人想出了一个更优雅的解决方案

4

7 回答 7

13

我认为有一个有用的List<T>.RemoveAll(Predicate<T> match)方法是为此设计的:http: //msdn.microsoft.com/en-us/library/wdka673a.aspx

于 2009-01-01T05:27:23.210 回答
7

这有点简单,但是当我打算从 IEnumerable/IList 中删除项目时,我通常只是复制一份:

foreach (MyObject myObject in new List<MyObject>(MyListOfMyObjects))
{
     if (condition) MyListOfMyObjects.Remove(myObject);
}

这不是最有效的方法,但它很容易阅读。过早的优化等等。

于 2009-01-05T06:15:47.890 回答
2

做相反的事情,创建一个新列表:

List myFilteredList = new List();
foreach (MyObject myObject in myListOfMyObjects)
{
     if (!condition) myFilteredList.Add(myObject);
}

然后在需要的地方使用新列表。

您还可以轻松地使用 LINQ 表达式,同样,反转条件。这具有不创建新结构的额外好处,但也有它是一个惰性可枚举的陷阱:

var myFilteredList = from myObject in myListOfMyObjects
                     where !condition
                     select myObject;

但是,如果您确实需要从列表中删除项目,我通常使用“创建一个新列表,然后重复并删除”的方法。

于 2009-01-01T05:20:25.737 回答
2

我不喜欢反向 for 循环的想法,因为它只适用于某些数据结构。

一般来说,我会使用第二种技术并将要删除的项目累积在一个单独的“待删除”集合中。如果删除会导致现有迭代无效(例如,任何平衡树集合都会发生这种情况),那么我看不到解决方法。

我偶尔使用的唯一其他技术是在找到要删除的第一个元素时重新开始整个迭代。如果您通过但没有找到任何要删除的项目,则该功能已完成。这是低效的,但如果从集合中删除一个项目可能会更改需要删除的项目集,则有时这是必要的。

于 2009-01-01T05:20:34.940 回答
2

我刚刚看到这篇文章,并认为我会分享。

void RemoveAll(object condition)  
{

    bool found = false;

    foreach(object thisObject in objects)    
    {

        if (condition)    
        {    
            objects.Remove(thisObject);

            found = true;

            break; //exit loop    
        }     
     }

    // Call again recursively

    if (found) RemoveAll(condition);

}
于 2011-05-25T20:49:30.427 回答
1

我很感激这现在可能已经死了,但我总是这样做的方式是:

foreach(MyListOfMyObjects 中的 MyObject myObject)
{

if (条件) MyListOfMyObjects.Remove(myObject);

休息;

}

对象被移除,然后循环退出,中提琴!

于 2010-04-29T17:10:37.560 回答
1

我有一本字典,想处理所有值。当每个值被处理时,它会从创建您讨论的问题的字典中删除自己。我做了以下事情:

foreach (var o in dictionary.Values.ToList())
{
  o.Dispose();
}
于 2012-01-13T12:40:49.267 回答