【问题标题】:Removing items from collection while iterating IEnumerable迭代 IEnumerable 时从集合中删除项目
【发布时间】:2014-04-19 14:05:02
【问题描述】:

我有以下代码:

foreach (var bar in dataFromDataFeed.Where(bar => bar.Key < fromTicks
                                                  || bar.Key > toTicks))
{
   dataFromDataFeed.Remove(bar.Key);
}

这是安全的还是我需要先将foreach 中的IEnumerable 转换为Dictionary&lt;T,U&gt;

谢谢。

【问题讨论】:

    标签: c# list iteration ienumerable


    【解决方案1】:

    不,这要么会炸毁你,要么会让你得到一个仍然有坏元素的结果。只需反转 Where 表达式:

    var filtered = dataFromDataFeed.Where(bar => bar.Key >= fromTicks && bar.Key <= toTicks);
    dataFromFeed = filtered.ToList();   // optional
    

    不清楚你是否真的需要更新列表,通常没有必要,因为你有一个非常好的枚举器,所以最后一个语句是// optional

    请记住,像在原始代码中那样使用 Remove() 具有 O(n*m) 复杂度,非常不好。使用 ToList() 只是 O(m) 但需要 O(m) 存储。内存交易速度是一个常见的程序员的决定,但这是一个灌篮高手,除非 m 很大(数亿并且你正在与 OOM 作斗争)或非常小。鉴于表达式,两者都不适用。

    【讨论】:

    • 感谢您的额外见解,我调整以避免Remove()
    • 嗯,您为什么选择使用删除的答案?这是个坏主意。
    • 公平点,在回答之前,如果源集合已排序,您是否知道反转表达式是否会对迭代的项目数产生影响?
    • 我最初选择了另一个答案,因为它首先出现并解决了问题,因为我没有要求最佳方法。但我很欣赏额外的想法,非常感谢。
    • @Matt - Using Remove is bad idea - 这完全取决于收藏品和收藏品的大小。所以,我在这里提供了发布内容的答案。我很欣赏 Hans 额外的 cmets,但这些从来都不是问题的一部分。无论如何选择答案完全取决于您。 :)
    【解决方案2】:

    在枚举时修改集合被认为是不好的做法,在许多情况下,这会导致InvalidOperationException 被抛出。

    您应该将值复制到另一个列表或数组中(例如,通过在您的 Where() 调用之后调用 ToList()),然后您将不会修改原始数据。

    foreach (var bar in dataFromDataFeed.Where(bar => bar.Key < fromTicks || bar.Key > toTicks).ToList())
    {
        dataFromDataFeed.Remove(bar.Key);
    }
    

    【讨论】:

      【解决方案3】:

      它会抛出一个错误,因为您正在迭代集合。枚举时不支持修改集合。

      使用 ToList()

      创建新列表
      foreach (var bar in dataFromDataFeed.Where(bar => bar.Key < fromTicks
                                               || bar.Key > toTicks).ToList())
      {
         dataFromDataFeed.Remove(bar.Key);
      }
      

      【讨论】:

        【解决方案4】:

        尽管Dictionary 几乎可以肯定已经包含了一个方法,该方法将所有的谓词函数用于每个项目并删除该谓词返回 true 的所有项目,但它没有。因此,如果一个人有一个Dictionary,其中包含一些与谓词匹配的项目,而另一些不匹配的项目,则获取仅包含不满足谓词的项目的字典的唯一方法是构建所有满足谓词的项目,然后从字典中删除列表中的所有项目,或者构建一个仅包含不满足谓词的项目的字典,并放弃原来的项目而使用新的项目。哪种方法更好将取决于要保留和丢弃的项目的相对数量。

        作为替代方案,可以切换到使用ConcurrentDictionary。与Dictionary 不同,ConcurrentDictionary 将允许在不使正在进行的任何枚举无效的情况下删除项目。如果仅在枚举项目时删除它们,我希望ConcurrentDictionary 能够完全按照人们的预期进行枚举。如果枚举一个项目有时会导致代码删除另一个项目,那么代码必须准备好删除尚未枚举的项目可能但不是必须导致该项目从枚举中省略。

        虽然Dictionary 通常比ConcurrentDictionary 快,但如果“删除...集合中的项目。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-12-18
          • 2010-12-13
          • 2011-03-03
          • 2012-05-13
          相关资源
          最近更新 更多