我正在寻找一种更好的模式,用于处理每个元素的列表,然后根据结果从列表中删除。
你不能在foreach (var element in X)中使用.Remove(element)(因为它会导致Collection被修改;枚举操作可能无法执行。例外)……你也不能使用for (int I = 0;i < elements.Count();i++)和. removeat (i),因为它破坏了你在集合中相对于i的当前位置。
有没有一种优雅的方式来做到这一点?
我正在寻找一种更好的模式,用于处理每个元素的列表,然后根据结果从列表中删除。
你不能在foreach (var element in X)中使用.Remove(element)(因为它会导致Collection被修改;枚举操作可能无法执行。例外)……你也不能使用for (int I = 0;i < elements.Count();i++)和. removeat (i),因为它破坏了你在集合中相对于i的当前位置。
有没有一种优雅的方式来做到这一点?
当前回答
这里还有一个没有提到的选项。
如果您不介意在项目的某个地方添加一些代码,您可以向List添加和扩展,以返回反向遍历列表的类的实例。
你可以这样使用它:
foreach (var elem in list.AsReverse())
{
//Do stuff with elem
//list.Remove(elem); //Delete it if you want
}
这是什么扩展看起来像:
public static class ReverseListExtension
{
public static ReverseList<T> AsReverse<T>(this List<T> list) => new ReverseList<T>(list);
public class ReverseList<T> : IEnumerable
{
List<T> list;
public ReverseList(List<T> list){ this.list = list; }
public IEnumerator GetEnumerator()
{
for (int i = list.Count - 1; i >= 0; i--)
yield return list[i];
yield break;
}
}
}
这基本上就是没有分配的list.Reverse()。
就像一些人提到的那样,你仍然会有一个一个地删除元素的缺点,如果你的列表非常长,这里的一些选项会更好。但我认为有些人希望list.Reverse()的简单性,没有内存开销。
其他回答
我发现自己遇到了类似的情况,我必须删除给定List<T>中的每n个元素。
for (int i = 0, j = 0, n = 3; i < list.Count; i++)
{
if ((j + 1) % n == 0) //Check current iteration is at the nth interval
{
list.RemoveAt(i);
j++; //This extra addition is necessary. Without it j will wrap
//down to zero, which will throw off our index.
}
j++; //This will always advance the j counter
}
在泛型列表上使用ToArray()可以在泛型列表上执行Remove(item):
List<String> strings = new List<string>() { "a", "b", "c", "d" };
foreach (string s in strings.ToArray())
{
if (s == "b")
strings.Remove(s);
}
这里还有一个没有提到的选项。
如果您不介意在项目的某个地方添加一些代码,您可以向List添加和扩展,以返回反向遍历列表的类的实例。
你可以这样使用它:
foreach (var elem in list.AsReverse())
{
//Do stuff with elem
//list.Remove(elem); //Delete it if you want
}
这是什么扩展看起来像:
public static class ReverseListExtension
{
public static ReverseList<T> AsReverse<T>(this List<T> list) => new ReverseList<T>(list);
public class ReverseList<T> : IEnumerable
{
List<T> list;
public ReverseList(List<T> list){ this.list = list; }
public IEnumerator GetEnumerator()
{
for (int i = list.Count - 1; i >= 0; i--)
yield return list[i];
yield break;
}
}
}
这基本上就是没有分配的list.Reverse()。
就像一些人提到的那样,你仍然会有一个一个地删除元素的缺点,如果你的列表非常长,这里的一些选项会更好。但我认为有些人希望list.Reverse()的简单性,没有内存开销。
在遍历列表时从列表中删除项的最佳方法是使用RemoveAll()。但是人们编写的主要问题是他们必须在循环中做一些复杂的事情和/或有复杂的比较情况。
解决方案是仍然使用RemoveAll(),但使用以下符号:
var list = new List<int>(Enumerable.Range(1, 10));
list.RemoveAll(item =>
{
// Do some complex operations here
// Or even some operations on the items
SomeFunction(item);
// In the end return true if the item is to be removed. False otherwise
return item > 5;
});
使用for循环反向迭代列表:
for (int i = safePendingList.Count - 1; i >= 0; i--)
{
// some code
// safePendingList.RemoveAt(i);
}
例子:
var list = new List<int>(Enumerable.Range(1, 10));
for (int i = list.Count - 1; i >= 0; i--)
{
if (list[i] > 5)
list.RemoveAt(i);
}
list.ForEach(i => Console.WriteLine(i));
或者,你可以使用RemoveAll方法和一个谓词来测试:
safePendingList.RemoveAll(item => item.Value == someValue);
下面是一个简单的例子:
var list = new List<int>(Enumerable.Range(1, 10));
Console.WriteLine("Before:");
list.ForEach(i => Console.WriteLine(i));
list.RemoveAll(i => i > 5);
Console.WriteLine("After:");
list.ForEach(i => Console.WriteLine(i));