从List<;T>;在c中做foreach

本文关键字:foreach 中做 List lt gt | 更新日期: 2023-09-27 18:24:55

我想知道在执行foreach时,从c#中的List中删除元素的最佳方法是什么。

这是一个代码示例。首先我创建了一个包含一些元素的列表,然后创建一个:

List<int> foo = new List<int>();
foo.Add(1);
foo.Add(2);
foo.Add(3);
foreach (int i in foo)
{
    if (i==2)
    {
        foo.Remove(i);
    }
}

当我运行这个时,我得到了一个InvalidOperationException,但如何用性能的方法来解决这个问题?

从List<;T>;在c中做foreach

如果在枚举时必须删除条目,请反向遍历列表,并删除需要删除的项。

for (var i = foo.Count-1 ; i >= 0 ; i--) {
    if (MustBeRemoved(foo[i])) {
        foo.RemoveAt(i);
    }
}

请注意,这是,而不是在您的帖子中需要的,因为您知道需要删除的值。

foo.RemoveAll(x => x == 2);

如果您决定不使用for和foreach;)

我认为您的实际用例比您所布局的更复杂。因此,让我们假设您实际上有一些条件在起作用,这些条件适用于每个元素,并且多个元素可以满足。我们将其称为谓词

List<T>公开了一个RemoveAll方法,该方法允许您提供谓词。然后删除与该谓词匹配的任何项。例如

Func<int, bool> isEven = i => i % 2 == 0;
List<int> ints = ...
ints.RemoveAll(item => isEven(item));
// ints will only contain odd numbers 

其他需要考虑的方法是在for循环中向后遍历列表并按索引删除,构建包含要删除的项目的第二个列表,然后在第二个循环中遍历第二个,从第一个列表中删除项目。或者,您可以编写一个查询来构建一个新的序列,其中包含您希望保留的项。

为什么需要循环?

foo.Remove(2);

我认为最好的方法是使用简单的for循环向后迭代。

for(int i = foo.Count-1; i>=0; i--)
    if(foo[i]==2) foo.RemoveAt(i);

将前臂更改为

foreach (int i in new List<int>(foo))

如果您想删除任意元素,而不仅仅是一个,您可以使用RemoveAll并指定一个谓词:

foo.RemoveAll(element => (element == 2));

您可以将要删除的项目添加到临时列表中,然后在循环后删除它们:

List<int> foo = new List<int>();
foo.Add(1);
foo.Add(2);
foo.Add(3);
List<int> remove = new List<int>();
foreach (int i in foo) {
  if (i==2) {
    remove.Add(i);
  }
}
foreach (int i in remove) {
  foo.Remove(i);
}

迭代列表时不能编辑列表。

考虑:

List<int> foo;
int[] bar = foo.ToArray();
foreach(int i in bar)
{
    if (i == 2)
    {
        foo.Remove(i);
    }
}

但是要注意:你应该向后走这个列表,因为从foo列表中删除一个项目将意味着条形列表不再与它对齐。(如果你不向后走,你将不得不跟踪删除的计数,并调整传递给remove调用的索引!)