在具有linq的foreach中从集合中删除

本文关键字:集合 删除 foreach linq | 更新日期: 2023-09-27 18:02:57

据我所知,这似乎不是一个安全的做法…

我在我的列表对象上有一个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 => y.SomeId == x.SomeId);是错误的,但从理论上讲,这就是我想要的。

我还玩弄了将使用过的SomeId推到idList然后每次检查它的想法,但这似乎很麻烦,并且想知道是否有更好的方法来处理我想要做的事情。

对不起,如果我没有解释得很好。如果有任何问题,请随意评论,我将在需要的地方回答/编辑。

在具有linq的foreach中从集合中删除

首先,由于这些原因,在示例中使用ForEach不是一个好主意。

你认为为每个剩余的SomeId遍历完整列表会有性能下降的想法是对的,但即使每次使列表变小,仍然需要对该子集进行另一次完整的迭代(如果它有效的话)。

正如在评论中指出的那样,SomeId上的GroupBy为您组织元素分组,并允许您有效地遍历给定SomeId的每个子集,如下所示:

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

Jon Skeet有一组关于如何实现Linq扩展的优秀文章。我强烈建议您查看一下,以便更好地理解为什么这样做会更有效。

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

GroupBy

这是我要使用的方法。您可以根据所需的属性对列表进行分组,并通过以这种方式形成的igrouing进行迭代

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);
}