2009-07-14 4 views
8

In sostanza, vorrei rimuovere un elemento da un elenco mentre si è all'interno del ciclo foreach. So che questo è possibile quando si utilizza un ciclo for, ma per altri scopi, vorrei sapere se questo è realizzabile utilizzando un ciclo foreach.Modifica raccolta quando si utilizza un ciclo foreach in C#

in Python possiamo raggiungere questo obiettivo nel modo seguente:

a = [1, 2, 3, 4, 5, 6, 7, 8, 9] 

for i in a: 
    print i 

    if i == 1: 
     a.pop(1) 

Questo ha pronunciato la seguente uscita

>>>1 
3 
4 
5 
6 
7 
8 
9 

Ma quando si fa qualcosa di simile in C#, ottengo un'InvalidOperationException, mi chiedevo se c'era un modo per aggirare questo, senza semplicemente utilizzare un ciclo for.

Il codice in C# che ho usato quando l'eccezione è stato gettato:

static void Main(string[] args) 
    { 
    List<string> MyList = new List<string>(new string[] { "1", "2", "3", "4", "5", "6", "7", "8", "9"}); 

    foreach (string Item in MyList) 
    { 
    if (MyList.IndexOf(Item) == 0) 
     { 
     MyList.RemoveAt(1); 
     } 

    Console.WriteLine(Item); 
    } 
    } 

Grazie in anticipo

risposta

25

Non si può fare questo. Dalla documentazione per IEnumerator<T>:

Un enumeratore rimane valido finché la collezione rimane invariato. Se le modifiche vengono apportate alla raccolta, come aggiungere, modificare o eliminare elementi , l'enumeratore è irrecuperabilmente invalidato e il suo comportamento non è definito.

Le alternative sono:

  • costruire una nuova lista di elementi da rimuovere, quindi rimuovere tutti dopo
  • Utilizzare un normale ciclo "for" e assicurarsi che siete attenti a non andare sopra lo stesso elemento due volte o mancante. (Hai detto che non vuole fare questo, ma quello che si sta cercando di fare proprio non funziona.)
  • costruire una nuova collezione che contiene solo gli elementi che si desidera mantenere

l'ultima di queste alternative è la soluzione LINQ-like, in cui tipicamente si dovrebbe scrivere:

var newList = oldList.Where(x => ShouldBeRetained(x)).ToList(); 

(. dove ShouldBeRetained è tutto ciò che la logica che si desidera, naturalmente) la chiamata alla ToList() è necessaria solo se si vuole realmente in una lista. Ciò porta a un codice più dichiarativo che è spesso più facile da leggere. Non riesco a indovinare quale sia il significato del loop originale (sembra piuttosto strano al momento) mentre se è possibile esprimere la logica puramente in termini di item, può essere molto più chiaro.

+0

Mi stavo chiedendo principalmente se mi fosse sfuggito qualcosa da qualche parte con l'istanza di foreach, ma se non è possibile, almeno è ora confermato! Grazie per la risposta – ThePower

1

Non è possibile modificare una raccolta in alcun modo quando si utilizza un ciclo foreach su di esso.

È possibile utilizzare un ciclo for e gestire l'indice per se stessi o creare una copia della raccolta e mentre si esegue il ciclo dell'originale, rimuovere gli elementi dalla copia corrispondente all'elemento nell'originale.

In entrambi i casi non è altrettanto chiaro o conveniente :).

6

Se tutto ciò che serve è quello di rimuovere tutti gli elementi che soddisfano una condizione è possibile utilizzare il metodo List<T>.RemoveAll:

List<string> MyList = new List<string>(new string[] { "1", "2", "3", "4", "5", "6", "7", "8", "9" }); 
MyList.RemoveAll(item => item == "1"); 

Si noti che questa modifica l'elenco iniziale.