【问题标题】:Removing from a collection while in a foreach with linq在使用 linq 的 foreach 中从集合中删除
【发布时间】:2015-07-15 17:10:32
【问题描述】:

据我了解,这似乎不是一种安全的做法...

我正在逐步执行的列表对象上有一个 foreach 循环。在该 foreach 循环中,我正在按 ID 查找记录。一旦我有了该 ID 返回的新记录列表,我就会进行一些解析并将它们添加到新列表中。

我想做的不是多次遍历同一个 ID。所以我的想法是把它从原始列表中删除。但是,这会导致错误......我明白为什么。

我的问题是...有没有安全的方法来解决这个问题?还是我应该重新调整我的思维过程?我想知道是否有人对如何解决此问题有任何经验或想法?

这是一个小伪代码:

_myList.ForEach(x => 
{
    List<MyModel> newMyList = _myList.FindAll(y => y.SomeId == x.SomeId).ToList();

    //Here is where I would do some work with newMyList

    //Now I am done... time to remove all records with x.SomeId
    _myList.RemoveAll(y => y.SomeId == x.SomeId);
});

我知道_myList.RemoveAll(y =&gt; y.SomeId == x.SomeId); 是错误的,但从理论上讲,这有点像我想要的。

我还玩弄过将使用过的 SomeId 推送到 idList 的想法,然后每次都检查它,但这似乎很麻烦,我想知道是否有更好的方法来处理我正在寻找的东西去做。

对不起,如果我没有很好地解释这一点。如果有任何问题,请随时发表评论,我将在需要时回答/进行编辑。

【问题讨论】:

  • 为什么不使用 GroupBy?您可以按 SomeId 对记录进行分组,然后在这些组上循环
  • 这是可能的。我将不得不尝试看看这是否对我有用。感谢您的意见!
  • 抱歉删除了我的回答。我看到你提到在你的问题中维护一个 ID 列表。 GroupBy 比维护 ID 列表要容易得多。
  • @SebastianoRoncato - 谢谢,这确实对我有用。如果您想发布作为答案,我很乐意将其标记为正确。

标签: c# linq foreach


【解决方案1】:

首先,在您的示例中使用ForEach 对于these reasons 来说并不是一个好主意。

您认为迭代每个剩余 SomeId 的完整列表存在性能下降是正确的,但即使每次都使列表更小仍然需要对该子集进行另一次完整迭代(如果它甚至工作的话)。

正如 cmets 中所指出的,SomeId 上的 GroupBy 为您将元素组织到分组中,并允许您有效地逐步遍历给定 SomeId 的每个子集,如下所示:

_myList.GroupBy(x => x.SomeId)
       .Select(g => DoSomethingWithGroupedElements(g));

Jon Skeet 有一组关于如何实现 Linq 扩展的优秀文章。我强烈推荐checking it out,以便更好地理解为什么这样做会更有效率。

【讨论】:

    【解决方案2】:

    首先,foreach 中的列表是不可变的,你不能添加或删除内容,也不能重写元素。有几种方法可以处理这种情况:

    分组方式

    这是我会使用的方法。您可以按所需的属性对列表进行分组,并遍历以这种方式形成的 IGrouping

    var groups = list.GroupBy(x => x.yourProperty);
    foreach(var group in groups)
    {
    //your code
    }
    

    不同属性列表

    您还可以将属性保存在另一个列表中,并循环浏览该列表而不是原始列表

    var propsList = list.Select(x=>x.yourProperty).Distinct();
    foreach(var prop in propsList)
    {
        var tmpList = list.Where(x=>x.yourProperty == prop);
        //your code
    }
    

    While循环

    这实际上会做你最初想要的,但性能可能不是最佳的

    while(list.Any())
    {
        var prop = list.First().yourProperty;
        var tmpList = list.Where(x=>x.yourProperty == prop);
        //your code
        list.RemoveAll(x=>x.yourProperty == prop);
    }
    

    【讨论】:

      猜你喜欢
      • 2014-03-08
      • 2013-06-07
      • 1970-01-01
      • 2012-12-24
      • 1970-01-01
      • 2010-12-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多