2013-02-27 5 views
1

Я действительно не знаю, почему цикл for только петли один раз. Я думаю, что логика правильная, ниже - код.C# почему List.Remove() прерывает 'for loop'?

// the list is named 'dataList' 

for(int i = 0 ; i < dataList.Count; i ++) 
{ 
    string[] data = dataList[i].Split('+'); 
    string[] wsno = data[0].Split(':'); 
    if(wsno[1].Equals(tbWorkSheet.Text)) 
    { 
     dataList.Remove(dataList[i]) <<<< remove string that has the same number 
     //data removed 
     //for loop ends up here idk why.. 
    } 
} 

dataList.Count будет размером с список.

дело такое. Я хочу удалить несколько строк, хранящихся в списке, каждая строка имеет свой номер группы. Итак, цикл for будет зацикливаться до последнего. но когда он найдет строку с тем же номером с нужной, она выполнит оператор if, который должен удалить его.

+0

'dataList.Count' является то, что значение конкретно? – Arran

+0

Сколько раз вы ожидаете его цикла? Выбрасывает исключение? –

+0

Как правило, вы выполняете итерацию в обратном направлении при удалении (то есть от count-1 до 0) ... это упрощает управление индексами. – spender

ответ

6

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

Например у вас есть 3 пунктов в списке с индексом 0, 1, 2.

Первая итерация: я = 0 Вы удаляете элемент с индексом 0. Список теперь элементы с индексом 0, 1 (кулак элемент удален).

Вторая итерация: i = 1. Обратите внимание, как элемент, расположенный в индексе 1, перемещается в 0. Пока наш индексный счетчик переходит в 1 от 0. Таким образом, мы «пропустим» этот элемент.

Если у вас есть только 2 элемента в своем списке, он сломается после первого удаления. Это потому, что счет уменьшается, а ваш индекс увеличивается.

Обращаясь в обратном порядке, вы устраните эту проблему.

List<int> list = new List<int> { 2, 1 }; 
for (int i = list.Count - 1; i >= 0; i--) 
{ 
    list.RemoveAt(i); 
} 

Edit: Как Ролинг упоминает вы можете идти вперед, если вы уменьшить счетчик при удалении элементов.

for (int i = 0; i < list.Count; i++) 
{ 
    list.RemoveAt(i--); 
} 
+1

Это канонический способ сделать это. –

+0

Я бы подумал о переходе и уменьшении 'i', когда я что-то удаляю, но, может быть, только если важно было переходить через список вперед. – Rawling

+0

wow спасибо бутон. это работает .. –

-5

Вы не можете изменить список в цикле for. Вы можете сохранить данные, которые хотите удалить в другом списке, а затем удалить их после выхода из цикла.

+1

Вы можете. Вы не можете в цикле foreach. – Corak

0

Ты забыл уменьшить i после удаления объекта. Это пропустит следующий пункт, поскольку все последующие позиции будут перенумерованы на 1.

0

Loop назад по списку:

for(int i = dataList.Count; i >= 0 ; i--) 
{ 
    string[] data = dataList[i].Split('+'); 
    string[] wsno = data[0].Split(':'); 
    if(wsno[1].Equals(tbWorkSheet.Text)) 
    { 
     dataList.RemoveAt(dataList[i]) <<<< remove string that has the same number 
     //data removed 
     //for loop ends up here idk why.. 
    } 
} 
+1

Это может по-прежнему вызывать проблемы, если в списке есть повторяющиеся записи - 'Remove' не может удалить элемент' i'th. 'RemoveAt' было бы лучше. – Rawling

3

Вы можете использовать List.RemoveAll универсальный метод. Метод удаляет из списка все элементы, соответствующие предикату. Метод подписи следующее:

INT List.RemoveAll (Predicate матч)

возвращает количество элементов, которые были удалены.

См MSDN: http://msdn.microsoft.com/en-US/library/wdka673a(v=vs.110).aspx

0

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

Может быть сделано аккуратно с помощью LINQ:

dataList = 
    dataList 
     .Select(x => new{ 
      dataItem = x, 
      secondWsno = x.Split('+').First().Split(':').Skip(1).First() 
     }) 
     .Where(x => !x.secondWsno.Equals(tbWorkSheet.Text)) 
     .ToList(); 
+0

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

+0

Легко переоценить стоимость таких операций. Я бы предпочел сделать это таким образом, пока не увидел, что это проблематично, но да, в случае незначительного удаления это может быть излишним. – spender