Modifying A Collection While Iterating Through It
有没有一个很好的模式允许我绕过无法删除对象,而我循环遍历一个可枚举的集合(例如,字典中的IList或KeyValuePairs)
例如,以下操作失败,因为它修改了在foreach
期间枚举的Listforeach (MyObject myObject in MyListOfMyObjects)
{
if (condition) MyListOfMyObjects.Remove(myObject);
}
过去我使用过两种方法。
我已经用反向for循环替换了foreach(以便在我删除对象时不更改我循环的任何索引)。
我还尝试存储一个新的对象集合,以便在循环中删除,然后循环遍历该集合并从原始集合中删除对象。
这些工作正常,但感觉都不好,我想知道是否有人提出了更多优雅的解决方案
答案 0 :(得分:13)
我认为这是一种有用的List<T>.RemoveAll(Predicate<T> match)
方法:http://msdn.microsoft.com/en-us/library/wdka673a.aspx
答案 1 :(得分:7)
这有点笨笨,但是当我打算从IEnumerable / IList中删除项目时,我通常只会复制一份:
foreach (MyObject myObject in new List<MyObject>(MyListOfMyObjects))
{
if (condition) MyListOfMyObjects.Remove(myObject);
}
这不是最有效的方法,但它很容易阅读。过早优化等等。
答案 2 :(得分: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;
但是,如果您确实需要从列表中删除项目,我通常会使用“创建新列表,然后重复并删除”方法。
答案 3 :(得分: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);
}
答案 4 :(得分:1)
我不喜欢反向for循环的想法,因为它只适用于某些数据结构。
一般情况下,我会使用第二种技术,并在一个单独的“待删除”集合中累积要删除的项目。如果删除可能导致现有的迭代失效(例如,对于任何平衡的树集合都会发生这种情况),那么我没有看到解决方法。
我偶尔使用的唯一其他技术是在找到要删除的第一个元素时重新启动整个迭代。如果你没有找到任何要删除的项目,那么该功能就完成了。这样效率很低,但有时候如果从集合中删除一个项目可能会改变需要删除的项目集。
答案 5 :(得分:1)
我很欣赏这可能已经死了,但我一直这样做的方式是:
foreach(MyListOfMyObjects中的MyObject myObject)
{
if(condition)MyListOfMyObjects.Remove(myObject);
<强>断; 强>
}
删除对象,然后循环退出,中提琴!
答案 6 :(得分:1)
我有一本字典,想要处理所有值。当处理每个值时,它将自己从字典中删除,从而产生您讨论的问题。我做了以下事情:
foreach (var o in dictionary.Values.ToList())
{
o.Dispose();
}