2016-01-28 74 views
3

我寫了一個函數去槽列表和刪除列表項目,如果遇到一些條件。我的程序崩潰了,過了一段時間,我斷定outer 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 [I]'的'if'訪問_after_你只是刪除了一個元素。 – 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); 
    } 
} 

問:

爲什麼for循環工作的另一個方向?

因爲循環從零運行到計數當索引不可用於刪除並且計數仍然保留時,會出現這種情況。例如:

如果您在列表中有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 *)。但是如果我是你的話,我會**自己來強化它。樂於幫助!:) –

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刪除元素,然後使用它。您需要先使用具有索引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); 
    } 
    }