迭代集合并修改它的最佳实践?

时间:2011-11-01 20:40:36

标签: c# collections foreach

我正在尝试迭代一组项目,执行一个操作,然后删除当前索引处的项目。

我目前实现的方式是这样的:

foreach (CormantRadPane pane in GetPanes().ToList())
{
    pane.Clear();
    StateManager.Remove(pane);
    LayoutManager.Instance.RegisteredPanes.Remove(pane);
    Items.Remove(pane);
}

通过调用ToList,我创建了一个集合的副本,但是保留了对第一个集合中每个对象的引用。这允许我迭代GetPanes的集合返回,而无需“技术上”修改集合。

这显然很容易让一些人难以追查错误。以干净的方式执行这种逻辑的标准方法是什么,但是对于正在发生的事情的复杂性也更清楚了?

我做了一些环顾四周,看到了诸如使用for循环并向后查看列表之类的东西,但这看起来真的很笨重。保持第二个项目列表“删除”然后在第一个循环完成后遍历该列表,删除第二个列表中找到的每个对象,我的感受大致相同。

你是如何处理的?感谢。

3 个答案:

答案 0 :(得分:5)

您可以创建变量并使用它,而不是当前的方法,我建议使用for循环来移除窗格,但是技巧只是反向迭代它:

var panes = GetPanes();
int count = panes.Count;
for(int i= count - 1; i>=0; i--)
{
       pane = panes[i];
       pane.Clear();
       StateManager.Remove(pane);
       LayoutManager.Instance.RegisteredPanes.Remove(pane);
       //Items.Remove(pane);
       Items.RemoveAt(i);
} 

调用Items.Remove(pane);需要O(n)(如果是列表)但是在使用Items.RemoveAt(i);的情况下它需要O(1),所以你当前的方法需要O(n ^ 2)但是如果你可以调用RemoveAt(索引)(你有一些列表,它们以相同的方式排序)你可以在O(n)中处理它。

答案 1 :(得分:0)

您可以使用linq列表扩展名,例如:

List<Item> items = GetItems(); items.ForEach(i => {i.DoStuff();i.DoStuff2(););}

至少这是我通常做的事情。

答案 2 :(得分:0)

你所指的是Robust Iterator,但我不相信C#和Java中提供的迭代器都很健壮。

如果您想要通过List强大地进行迭代,则可以通过跟踪列表的索引来实现自己的Robust Iterator。这可能不适用于定义次序较少的集合以及某些非随机访问可迭代的数据库结果集。

也许另一个回答者可以帮助您找到在特定情况下不需要强大迭代器的方法。