C# 有效地从'中删除项目;foreach&x27;

C# 有效地从'中删除项目;foreach&x27;,c#,.net,collections,C#,.net,Collections,目前,我能想到的最好的办法是: bool oneMoreTime = true; while (oneMoreTime) { ItemType toDelete=null; oneMoreTime=false; foreach (ItemType item in collection) { if (ShouldBeDeleted(item)) { toDelete=item; brea

目前,我能想到的最好的办法是:

bool oneMoreTime = true;
while (oneMoreTime)
{
    ItemType toDelete=null;
    oneMoreTime=false;
    foreach (ItemType item in collection)
    {
        if (ShouldBeDeleted(item))
        {
            toDelete=item;
            break;
        }
    }
    if (toDelete!=null)
    {
        collection.Remove(toDelete);
        oneMoreTime=true;
    }
}

我知道这里至少有一个额外的变量,但我加入它是为了提高算法的可读性。

当我完成键入时,我记得有lambda方法可以做到这一点

collection.RemoveAll(i=>ShouldBeDeleted(i));
更好的方法?

最好的方法是“RemoveAll”

另一种常见技术是:

var itemsToBeDeleted = collection.Where(i=>ShouldBeDeleted(i)).ToList();
foreach(var itemToBeDeleted in itemsToBeDeleted)
    collection.Remove(itemToBeDeleted);
另一种常见的技巧是使用“for”循环,但要确保返回:

另一种常见技术是将未删除的项目添加到新集合中:

var newCollection = new List<whatever>();
foreach(var item in collection.Where(i=>!ShouldBeDeleted(i))
    newCollection.Add(item);

var newCollection=ImmutableCollection.Empty;
foreach(oldCollection.Where(i=>!ShouldBeDeleted(i))中的var项)
newCollection=newCollection.Add(项);

完成后,您将有两个集合。新集合删除了项,旧集合与以前一样。

lambda方法很好。您还可以使用常规for循环,您可以迭代for循环在循环本身中使用的列表,这与foreach循环不同

for (int i = collection.Count-1; i >= 0; i--)
{
    if(ShouldBeDeleted(collection[i])
        collection.RemoveAt(i);
}

这里我假设集合是一个arraylist,如果您使用的是不同的数据结构,那么代码可能会有点不同。

您不能从
foreach
循环中的集合中删除(除非它是一个非常特殊的集合,具有特殊的枚举器)。如果在枚举集合时修改了集合,则BCL集合将引发异常

您可以使用
for
循环来删除单个元素并相应地调整索引。但是,这样做很容易出错。根据基础集合的实现情况,删除单个元素的成本也可能会很高。例如,删除
列表的第一个元素将复制所有剩余元素正在删除列表中的元素

最好的解决方案通常是基于旧集合创建新集合:

var newCollection = collection.Where(item => !ShouldBeDeleted(item)).ToList();

使用
ToList()
ToArray()
Where()
子句返回的
IEnumerable
创建新集合或初始化特定集合类型。

对于
循环,向后
的向前变化:

for (int i = 0; i < collection.Count; )
    if (ShouldBeDeleted(collection[i]))
        collection.RemoveAt(i)
    else
        i++;
for(int i=0;i
仅供参考的可能副本:可以将其转换为方法组.collection.RemoveAll(ShouldBeDeleted)。您是否曾使用foreach使用过
Reverse
扩展?我刚刚在这里遇到过它?为什么它不是一个更广泛使用的选项?是否存在某种严重的性能影响或正在发生的事情?@ppumkin:尝试为一个未实现的
IEnumerable
编写一个
Reverse
实现ent
IList
ICollection
,等等。您的实现的内存和时间性能如何?我的实现对时间或资源不是很关键。我使用的是列表上Linq中的
IEnumerable.Reverse
扩展,在
foreach
中似乎工作正常-这就是为什么我问,为什么不使用它一个更频繁的示例,与(i到0)的所有这些示例相反相反,就像在你的答案中一样。使用反向扩展是一个有效的选项吗?你能将它添加到你的答案中吗?或者将Linq的反向扩展与foreach结合使用有什么问题吗?只是想,你的意见会因为你的经验而最有分量。@ppumkin:因为反向使用IEnumerable require创建整个IEnumerable的副本(因此可以在foreach循环中修改原始集合),这没有什么意义;您也可以只复制集合而不反转它,可能是通过调用
ToList
。为破坏Eric的课程向他道歉。@BKSpurgeon:确实如此!所有高于已删除元素的元素都需要向下移动一点。如果您需要高效地执行此操作,请执行此操作不要使用列表。请使用无序类型,如哈希集,或使用高效支持此操作的有序类型,如双链接列表、可分类数据块等。
for (int i = collection.Count-1; i >= 0; i--)
{
    if(ShouldBeDeleted(collection[i])
        collection.RemoveAt(i);
}
var newCollection = collection.Where(item => !ShouldBeDeleted(item)).ToList();
for (int i = 0; i < collection.Count; )
    if (ShouldBeDeleted(collection[i]))
        collection.RemoveAt(i)
    else
        i++;