.NET - 从'foreach'循环中的List <T>中删除

BCS*_*BCS 46 .net foreach remove-method

我有我希望看起来像这样的代码:

List<Type> Os;

...

foreach (Type o in Os)
    if (o.cond)
        return;  // Quitting early is important for my case!
    else
        Os.Remove(o);

... // Other code
Run Code Online (Sandbox Code Playgroud)

这不起作用,因为当您foreach在该列表上的循环内时,无法从列表中删除:

有没有一种解决问题的常用方法?

如果需要,我可以切换到不同的类型.

选项2:

List<Type> Os;

...

while (Os.Count != 0)
     if (Os[0].cond)
         return;
     else
         Os.RemoveAt(0);

... // Other code
Run Code Online (Sandbox Code Playgroud)

丑陋,但它应该工作.

Jon*_*n B 58

您可以向后遍历列表:

for (int i = myList.Count - 1; i >= 0; i--)
{
    if (whatever) myList.RemoveAt(i);
}
Run Code Online (Sandbox Code Playgroud)

当您发现想要在您找不到要移除的项目时退出的评论时,那么仅使用while循环将是最佳解决方案.

  • 他向后迭代以将正确的索引"i"保留在列表中.如果你向前迭代,你需要回溯一次(i--)进行每次删除以避免跳过项目. (5认同)

Use*_*ser 55

在foreach循环内部,你永远不应该从正在迭代的集合中删除任何东西.它基本上就像锯你所坐的那个分支.

使用你的替代方案.这是要走的路.

  • 锯切分支隐喻的+1.非常好. (45认同)

Luk*_*keH 31

你真的需要在foreach循环中这样做吗?

这将获得与示例相同的结果,即从列表中删除所有项目,直到匹配条件的第一个项目(或删除所有项目,如果它们都不匹配条件).

int index = Os.FindIndex(x => x.cond);

if (index > 0)
    Os.RemoveRange(0, index);
else if (index == -1)
    Os.Clear();
Run Code Online (Sandbox Code Playgroud)


Mil*_*ous 15

我是一名Java程序员,但这样的工作原理:

List<Type> Os;
List<Type> Temp;
...
foreach (Type o in Os)
    if (o.cond)
        Temp.add(o);
Os.removeAll(Temp);  
Run Code Online (Sandbox Code Playgroud)

  • 除非你使用微小的集合,**这是低效的**.虽然Jon B的解决方案是O(n),但这个解决方案是[O(2n + m)](http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14 /java/util/AbstractCollection.java#AbstractCollection.removeAll%28java.util.Collection%29),其中*m*是匹配项的数量.我说*会*,因为它甚至不能用于.net.在Java中没有`List <T> .RemoveAll(ICollection <T>)`.**看看@dirkgently的解决方案**.不幸的是`RemoveAll`不会返回被删除的元素,比如`IEnumerable <T>`. (3认同)

Anz*_*rio 13

我的分析库只是遇到了这个问题.我试过这个:

for (int i = 0; i < list.Count; i++)
{                
   if (/*condition*/)
   {
       list.RemoveAt(i);
       i--;
   }
}
Run Code Online (Sandbox Code Playgroud)

这很简单,但我没有想到任何突破点.


son*_*njz 12

这里是最简单的解决与simpliest WHY

问题:

通常,我们从原始列表中删除,这会产生维护列表计数和迭代器位置的问题.

List<Type> Os = ....;
Os.ForEach(
    delegate(Type o) {
        if(!o.cond) Os.Remove(o);
    }
);
Run Code Online (Sandbox Code Playgroud)

解决方案 - LINQ.ForEach:

请注意我添加的所有内容ToList().这将创建一个您执行ForEach的新列表,因此您可以删除原始列表,但继续遍历整个列表.

List<Type> Os = ....;
Os.ToList().ForEach(
    delegate(Type o) {
        if(!o.cond) Os.Remove(o);
    }
);
Run Code Online (Sandbox Code Playgroud)

解决方案 - 常规foreach:

这种技术也适用于常规foreach语句.

List<Type> Os = ....;
foreach(Type o in Os.ToList()) {
  if(!o.cond) Os.Remove(o);
}
Run Code Online (Sandbox Code Playgroud)

请注意,如果原始List包含struct元素,则此解决方案将无效.


Day*_*mer 11

我知道你要求别的东西,但如果你想有条件地删除一堆元素你可以使用lambda表达式:

Os.RemoveAll(o => !o.cond);
Run Code Online (Sandbox Code Playgroud)


dir*_*tly 9

 Os.RemoveAll(delegate(int x) { return /// });
Run Code Online (Sandbox Code Playgroud)