我正在寻找一种更好的模式,用于处理每个元素的列表,然后根据结果从列表中删除。

你不能在foreach (var element in X)中使用.Remove(element)(因为它会导致Collection被修改;枚举操作可能无法执行。例外)……你也不能使用for (int I = 0;i < elements.Count();i++)和. removeat (i),因为它破坏了你在集合中相对于i的当前位置。

有没有一种优雅的方式来做到这一点?


当前回答

 foreach (var item in list.ToList()) {
     list.Remove(item);
 }

如果你将".ToList()"添加到列表(或LINQ查询的结果)中,你可以直接从"list"中删除"item",而不用担心"Collection was modified;枚举操作不能执行"错误。编译器会复制“list”,这样你就可以安全地删除数组了。

虽然这种模式不是超级高效,但它有一种自然的感觉,并且对于几乎任何情况都足够灵活。例如,当您想要将每个“项”保存到一个DB,并仅当DB保存成功时才将其从列表中删除。

其他回答

如果决定删除哪些项的函数没有副作用,也没有改变项(这是一个纯函数),一个简单有效的(线性时间)解决方案是:

list.RemoveAll(condition);

如果有副作用,我会使用如下方法:

var toRemove = new HashSet<T>();
foreach(var item in items)
{
     ...
     if(condition)
          toRemove.Add(item);
}
items.RemoveAll(toRemove.Contains);

这仍然是线性时间,假设哈希是好的。但是由于hashset,它增加了内存使用。

最后,如果你的列表只是一个IList<T>,而不是一个list <T>,我建议我的答案,我怎么能做这个特殊的foreach迭代器?与许多其他答案的二次运行时相比,给出IList<T>的典型实现,它将具有线性运行时。

假设predicate是一个元素的布尔属性,如果它为真,则该元素应该被移除:

        int i = 0;
        while (i < list.Count())
        {
            if (list[i].predicate == true)
            {
                list.RemoveAt(i);
                continue;
            }
            i++;
        }
List<T> TheList = new List<T>();

TheList.FindAll(element => element.Satisfies(Condition)).ForEach(element => TheList.Remove(element));

选择您确实需要的元素,而不是试图删除您不想要的元素。这比删除元素要容易得多(通常也更有效)。

var newSequence = (from el in list
                   where el.Something || el.AnotherThing < 0
                   select el);

我想把这篇评论作为对Michael Dillon下面评论的回应,但它太长了,可能在我的回答中有用:

就我个人而言,我从来不会一个接一个地删除项,如果你确实需要删除,那么调用RemoveAll,它接受一个谓词,只重新排列一次内部数组,而remove则是一个数组。为您删除的每个元素复制操作。RemoveAll大大提高了效率。

当你在一个列表上向后迭代时,你已经有了你想要删除的元素的索引,所以调用RemoveAt会更有效,因为remove首先遍历列表来找到你想要删除的元素的索引,但你已经知道那个索引。

总而言之,我不认为有任何理由在for循环中调用Remove。理想情况下,如果可能的话,使用上面的代码根据需要从列表中输入元素,这样就根本不需要创建第二个数据结构。

我希望“模式”是这样的:

foreach( thing in thingpile )
{
    if( /* condition#1 */ )
    {
        foreach.markfordeleting( thing );
    }
    elseif( /* condition#2 */ )
    {
        foreach.markforkeeping( thing );
    }
} 
foreachcompleted
{
    // then the programmer's choices would be:

    // delete everything that was marked for deleting
    foreach.deletenow(thingpile); 

    // ...or... keep only things that were marked for keeping
    foreach.keepnow(thingpile);

    // ...or even... make a new list of the unmarked items
    others = foreach.unmarked(thingpile);   
}

这将使代码与程序员大脑中进行的过程保持一致。