我有一个遍历列表中元素的循环。我需要根据某些条件从循环中删除此列表中的元素。当我尝试在C#中执行此操作时,我得到一个例外。显然,不允许从列表中删除正在迭代的元素。使用foreach循环观察到该问题。有没有什么标准方法可以解决这个问题?
注意:我能想到的一个解决方案是仅为迭代目的创建列表副本,并从循环内的原始列表中删除元素。我正在寻找一种更好的解决方法。
答案 0 :(得分:16)
使用List<T>
时ToArray()
方法在这种情况下有很大帮助:
List<MyClass> items = new List<MyClass>();
foreach (MyClass item in items.ToArray())
{
if (/* condition */) items.Remove(item);
}
替代方法是使用for循环而不是foreach,但是每当删除元素时,你必须减少索引变量,即
。List<MyClass> items = new List<MyClass>();
for (int i = 0; i < items.Count; i++)
{
if (/* condition */)
{
items.RemoveAt(i);
i--;
}
}
答案 1 :(得分:13)
如果您的列表是实际的List<T>
,那么您可以使用内置的RemoveAll
方法根据谓词删除项目:
int numberOfItemsRemoved = yourList.RemoveAll(x => ShouldThisItemBeDeleted(x));
答案 2 :(得分:5)
您可以使用整数索引删除项目:
List<int> xs = new List<int> { 1, 2, 3, 4 };
for (int i = 0; i < xs.Count; ++i)
{
// Remove even numbers.
if (xs[i] % 2 == 0)
{
xs.RemoveAt(i);
--i;
}
}
这可能很难阅读并且难以维护,特别是如果循环中的逻辑变得更复杂。
答案 3 :(得分:4)
您可以使用LINQ通过过滤掉项目来将新列表替换为初始列表:
IEnumerable<Foo> initialList = FetchList();
initialList = initialList.Where(x => SomeFilteringConditionOnElement(x));
// Now initialList will be filtered according to the condition
// The filtered elements will be subject to garbage collection
这样您就不必担心循环了。
答案 4 :(得分:2)
另一个技巧是向后循环遍历列表。删除项目不会影响在循环的其余部分中遇到的任何项目。
我不推荐这个或其他任何东西。您需要的所有内容都可以使用LINQ语句来过滤您的要求列表。
答案 5 :(得分:1)
建议的解决方案是将您要删除的所有元素放在一个单独的列表中,在第一个循环之后,放置第二个循环,迭代删除列表并从第一个列表中删除这些元素。
答案 6 :(得分:1)
你可以这样用foreach迭代:
List<Customer> custList = Customer.Populate();
foreach (var cust in custList.ToList())
{
custList.Remove(cust);
}
注意:在变量列表上的ToList,它会遍历ToList创建的列表,但会从原始列表中删除项目。
希望这有帮助。
答案 7 :(得分:0)
您收到错误的原因是因为您正在使用foreach循环。如果你考虑foreach循环如何工作,这是有道理的。 foreach循环调用List上的GetEnumerator方法。如果您在哪里更改List中的元素数,则foreach循环保持的Enumerator将没有正确数量的元素。如果删除了一个元素,则会抛出null异常错误,如果添加了一个元素,则循环将丢失一个项目。
如果您喜欢Linq和Lamda的表达方式,我会推荐Darin Dimitrov解决方案,否则我会使用Chris Schmich提供的解决方案。