Проблемы с удалением элементов из списка при итерации по списку - PullRequest
16 голосов
/ 23 августа 2010

У меня есть цикл, который перебирает элементы в списке. Я обязан удалить элементы из этого списка в цикле на основе определенных условий. Когда я пытаюсь сделать это в C #, я получаю исключение. по-видимому, не разрешается удалять элементы из списка, который перебирается. Проблема наблюдалась с циклом foreach. Есть ли какой-нибудь стандартный способ обойти эту проблему?

Примечание. Одним из решений, которое я мог бы придумать, является создание копии списка исключительно для итерационных целей и удаление элементов из исходного списка в цикле. Я ищу лучший способ справиться с этим.

Ответы [ 8 ]

16 голосов
/ 23 августа 2010

При использовании 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--;
    }
}
13 голосов
/ 23 августа 2010

Если ваш список является действительным List<T>, вы можете использовать встроенный метод RemoveAll для удаления элементов на основе предиката:

int numberOfItemsRemoved = yourList.RemoveAll(x => ShouldThisItemBeDeleted(x));
5 голосов
/ 23 августа 2010

Вы можете использовать целочисленную индексацию для удаления элементов:

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;
    }
}

Это может быть странно читать и трудно поддерживать, тем не менее, особенно если логика цикла становится более сложной.

4 голосов
/ 23 августа 2010

Вы можете использовать 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

Таким образом, вам не нужно беспокоиться о петлях.

2 голосов
/ 23 августа 2010

Еще одна хитрость заключается в том, чтобы перебирать список в обратном направлении. Удаление элемента не повлияет на элементы, с которыми вы столкнетесь в оставшейся части цикла.

Я не рекомендую это или что-то еще, хотя. Все, для чего это нужно, возможно, можно сделать с помощью операторов LINQ, чтобы отфильтровать список по вашим требованиям.

1 голос
/ 15 декабря 2016

Вы можете выполнить итерацию с foreach следующим образом:

List<Customer> custList = Customer.Populate();

foreach (var cust in custList.ToList())

{

        custList.Remove(cust);

}

Примечание: ToList в списке переменных, это перебирает список, созданный ToList, но удаляет элементы из исходного списка.

Надеюсь, это поможет.

1 голос
/ 23 августа 2010

Рекомендуемое решение - поместить все ваши элементы, которые вы хотите удалить, в отдельный список, а после первого цикла поместить второй цикл, в котором вы выполняете итерацию по списку удаления и удаляете эти элементы из первого списка.

0 голосов
/ 23 августа 2010

Причина, по которой вы получаете ошибку, заключается в том, что вы используете цикл foreach. Если вы думаете о том, как работает цикл foreach, это имеет смысл. Цикл foreach вызывает метод GetEnumerator в списке. Если вы измените количество элементов в списке, то перечислитель, который содержит цикл foreach, не будет иметь правильное количество элементов. Если вы удалите элемент, возникнет ошибка с нулевым исключением, а если вы добавите элемент, цикл пропустит элемент.

Если вам нравятся выражения Linq и Lamda, я бы порекомендовал решение Дарина Димитрова, иначе я бы использовал решение, предоставленное Крисом Шмихом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...