2016-01-28 1 views
3

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

// Lijst is a list of a struct that contains a value .scanned and .price 

for (int i = 0; i < Lijst.Count; i++) 
    { 
    if (Lijst[i].scanned == false) 
    { 
    // (removed deletion of list item i here) 
    if (Lijst[i].price > (int)nudMinimum.Value) 
     { 
     Totaal++; 
     lblDebug.Text = Totaal.ToString(); 
     } 
    Lijst.RemoveAt(i); //<-moved to here 
    } 
    } 

Теперь я задаюсь вопросом, что правильно делать, не получая индекс из ошибок диапазона.

+3

Выполните цикл от графа до 0 –

+0

отметить также, что 'Lijst [я]' в 'if' обращается к элементу _после_, который вы только что сняли. – CompuChip

+0

Почему бы другое направление для цикла работать? – user3800527

ответ

1

Вы могли бы искать для этого

for (int i = Lijst.Count - 1 ; i >= 0 ; i--) 
{ 
    if (Lijst[i].scanned == false) 
    { 
     if (Lijst[i].price > (int)nudMinimum.Value) 
     { 
      Totaal++; 
      lblDebug.Text = Totaal.ToString(); 
     } 
     Lijst.RemoveAt(i); 
    } 
} 

Вопрос в комментарии:

почему бы другое направление для работы контура?

Потому что, когда цикл запущен от нуля до графа Возникает ситуация, когда индекс недоступен для удаления, и счет все еще остается. Например:

Если у вас есть 10 элементов в списке, цикл начинается с 0 и будет удалять 0,1,2,3,4, а теперь левый элемент равен 5, а индекс также равен 5, это также удалит этот элемент , После этого, когда значение цикла достигает 6, а элемент слева равен 4. Тогда это создаст проблему. и это вызовет ошибку. т.е. индекс вне диапазона

+0

Вы хотите запустить этот цикл в 'Lijst.Count-1' ... –

+0

@ user3800527 - Он оценивается только один раз в начале. – Enigmativity

+0

не нужно устанавливать 'lblDebug.Text' каждую итерацию – Byyo

-1
List<string> list = new List<string>(); 
     list.Add("sasa"); 
     list.Add("sames"); 
     list.Add("samu"); 
     list.Add("james"); 
     for (int i = list.Count - 1; i >= 0; i--) 
     { 

      list.RemoveAt(i); 

     } 

How to Delete Items from List

0

Обычно, если вы хотите удалить из списка все элементы, которые соответствуют предикат, вы бы использовать List<T>.RemoveAll(), например:

List<int> test = Enumerable.Range(0, 10).ToList(); 

test.RemoveAll(value => value%2 == 0); // Remove all even numbers. 

Console.WriteLine(string.Join(", ", test)); 

Однако , кажется, вам нужно сделать некоторую дополнительную обработку. У вас есть два варианта:

  1. Сделайте это в два шага; сначала используйте RemoveAll(), чтобы удалить ненужные элементы, затем перейдите по списку, чтобы обработать остальные предметы отдельно.
  2. Петля назад от List.Count-1 до 0 вместо.
+0

Вы поднимаете действительную точку, но мне интересно, соответствует ли она требованию OP при подсчете общего количества удалений. –

+0

@KonradViltersten Следовательно, мой комментарий о выполнении дополнительной обработки (см. Мои варианты 1. и 2. в ответе) –

1

Проблема заключается в том, что при удалении элемента номер 5 список становится короче, а номер элемента 6 теперь равен 5, число 7 становится 6-м и т. Д. Однако, если вы запустите цикл назад, число будет сохранено как и ожидалось.

for(int i = donkeys.Count - 1; i >= 0; i++) 
    if(donkeys[i] == some condition here) 
    donkeys.RemoveAt(i); 

Однако, это подход, похожий на босса. Есть лучшие способы. У вас есть ответ, но я хотел бы предложить подход на основе LINQ.

int Totaal = Lijst 
    .Where(item => item.scanned) 
    .Where(item => item.price > (int)nudMinimum.Value) 
    .Count(); 

Lijst = Lijst.Where(item => !item.scanned).ToList() 

Кроме того, в качестве примечания стороны, интересно, находите ли вы ниже более читаемым. Рассмотрим следующее различное наименование (как относительно языка, так и капитализации).

List<Item> items = ...; 
int minimum = (int)nudMinimum.Value; 

int total = items 
    .Where(item => item.scanned) 
    .Where(item => item.price > minimum) 
    .Count(); 

items = items 
    .Where(item => !item.scanned) 
    .ToList(); 
+0

Хмм я не настолько глубоко в Linq, я признаю, что код выглядит хорошо – user3800527

+0

@ user3800527 Да, я вроде как от петель. Как я уже сказал, если вы не решитесь пойти на LINQ (что вам нужно, потому что это очень полезно, и все это используют), просто верните свой цикл из последнего элемента до нуля (не из того, что он из * .Count -1 * и вниз до * i> = 0 *). Но если бы я был вами, я бы ** принудил себя к LINQing. Рад помочь!:) –

2

Почему бы не написать List<T>.RemoveAll()?

https://msdn.microsoft.com/en-us/library/wdka673a(v=vs.110).aspx

В вашем случае

Lijst.RemoveAll(item => some condition); 

Э.Г.

// Count all the not scanned items each of them exceeds nudMinimum.Value 
    lblDebug.Text = Lijst 
    .Where(item => !item.scanned && item.price > (int)nudMinimum.Value) 
    .Count() 
    .ToString(); 

    // Remove all not scanned items 
    Lijst.RemoveAll(item => !item.scanned); 
+0

Мне еще нужно сделать некоторые вычисления на нем, на самом деле немного больше, чем в вышеприведенном коде, поэтому я петлю через них – user3800527

+0

@ user3800527: что такое фактическое состояние, пожалуйста? –

0

Ваш код является некоторым, как не в надлежащем формате. сначала вы удалили элемент списка, а затем попытались поймать цену за удаленный элемент. Как это возможно.

поэтому вы можете написать таким образом.

for (int i = 0; i < Lijst.Count; i++) 
    { 
    if (Lijst[i].scanned == false) 
    { 
     if (Lijst[i].price > (int)nudMinimum.Value) 
     { 
     Totaal++; 
     lblDebug.Text = Totaal.ToString(); 
     } 
    Lijst.RemoveAt(i);   
    } 
    } 
1

здесь вы идете

// 1. Count items 
lblDebug.Text = Lijst.Count(x => x.price > (int)nudMinimum.Value && !x.scanned).ToString(); 
//2. Remove items 
Lijst.RemoveAll(x => !x.scanned); 
1

Сначала Вы удаляете элемент с индексом я, а затем использовать его. Сначала вы должны выполнить свой процесс с элементом, имеющим индекс i, а затем удалить его. Ваш код будет выглядеть следующим образом:

for (int i = 0; i < Lijst.Count; i++) 
    { 
    if (Lijst[i].scanned == false) 
    { 

    if (Lijst[i].price > (int)nudMinimum.Value) 
     { 
     Totaal++; 
     lblDebug.Text = Totaal.ToString(); 
     } 
Lijst.RemoveAt(i); 
    } 
    } 
Смежные вопросы