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

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

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


当前回答

你不能使用foreach,但是当你删除一个项目时,你可以向前迭代并管理你的循环索引变量,如下所示:

for (int i = 0; i < elements.Count; i++)
{
    if (<condition>)
    {
        // Decrement the loop counter to iterate this index again, since later elements will get moved down during the remove operation.
        elements.RemoveAt(i--);
    }
}

注意,一般来说,所有这些技术都依赖于被迭代的集合的行为。这里显示的技术将与标准List(T)一起工作。(很有可能编写自己的集合类和迭代器,允许在foreach循环期间删除项。)

其他回答

在遍历列表时从列表中删除项的最佳方法是使用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循环,并使用RemoveAt(i)来删除元素。

在泛型列表上使用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);
        }

在c#中,一个简单的方法是标记你想要删除的,然后创建一个新的列表来迭代…

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

或者更简单的使用linq....

list.RemoveAll(p=>p.Delete);

但是值得考虑的是,如果其他任务或线程在你忙着删除的同时访问同一个列表,那么可以使用ConcurrentList来代替。

复制您正在迭代的列表。然后从副本中删除并与原件相互作用。倒退是令人困惑的,并且在并行循环时不能很好地工作。

var ids = new List<int> { 1, 2, 3, 4 };
var iterableIds = ids.ToList();

Parallel.ForEach(iterableIds, id =>
{
    ids.Remove(id);
});