2009-09-26 17 views
21

Ho un hashset in C# che sto rimuovendo da se viene soddisfatta una condizione mentre si esegue l'iterazione con l'hashset e non è possibile farlo utilizzando un ciclo foreach come di seguito.HashSet Iterare mentre si rimuovono gli articoli in C#

foreach (String hashVal in hashset) 
{ 
    if (hashVal == "somestring") 
    { 
      hash.Remove("somestring"); 
    } 
} 

Quindi, come posso rimuovere gli elementi durante l'iterazione?

risposta

44

Utilizzare il metodo RemoveWhere di HashSet invece:

hashset.RemoveWhere(s => s == "somestring"); 

Si specifica una condizione/predicato come parametro per il metodo. Tutti gli elementi nel hashset che corrisponde al predicato saranno rimossi.

Ciò evita il problema di modificare l'hashset mentre viene iterato.


In risposta al tuo commento:

's'

rappresenta la voce corrente in corso di valutazione all'interno del hashset.

Il codice di cui sopra è equivalente a:

hashset.RemoveWhere(delegate(string s) {return s == "somestring";}); 

o:

hashset.RemoveWhere(ShouldRemove); 

public bool ShouldRemove(string s) 
{ 
    return s == "somestring"; 
} 

EDIT: Qualcosa è appena venuto in mente: poiché HashSet è un insieme che non contiene valori duplicati, basta chiamare hashset.Remove("somestring"). Non c'è bisogno di farlo in un ciclo perché non ci sarà mai più di una singola partita.

+0

Grazie cosa rappresenterebbe la s? – aHunter

+0

's' rappresenta l'elemento corrente all'interno dell'hashset in fase di valutazione. Vedi la risposta aggiornata. – adrianbanks

1

Di solito quando voglio iterare su qualcosa e rimuovere i valori che uso:

For (index = last to first) 
     If(ShouldRemove(index)) Then 
      Remove(index) 
+0

Grazie so che posso utilizzare un ciclo for non è possibile accedere a un hashset utilizzando una posizione di indice in questo modo. Se stavo usando il C++, vorrei semplicemente usare dei puntatori che non posso fare questo in C#. – aHunter

+0

Si può anche prendere in considerazione l'utilizzo di una diversa struttura dati, se possibile. – Nescio

8

Non è possibile rimuovere elementi da una raccolta mentre si esegue il ciclo su di esso con un enumeratore. Due approcci per risolvere questo sono:

  • Loop all'indietro oltre la raccolta utilizzando un normale elementi indicizzati per-loop (che a mio avviso non è un'opzione nel caso di un HashSet)
  • Loop sulla raccolta, aggiungere essere rimossi per un'altra raccolta, quindi avvolgere il -collection "ad-essere eliminati" e rimuovere gli elementi:

esempio del secondo approccio:

HashSet<string> hashSet = new HashSet<string>(); 
hashSet.Add("one"); 
hashSet.Add("two"); 

List<string> itemsToRemove = new List<string>(); 
foreach (var item in hashSet) 
{ 
    if (item == "one") 
    { 
     itemsToRemove.Add(item); 
    } 
} 

foreach (var item in itemsToRemove) 
{ 
    hashSet.Remove(item); 
} 
+0

Il programma ha già abbastanza memoria, quindi preferirei non usare un altro elenco. Grazie – aHunter

+0

Eviterei di usare due cicli foreach - un ciclo foreach è sufficiente, vedere la mia risposta – javapowered

4

vorrei evitare di usare loop di due foreach - un ciclo foreach è sufficiente:

HashSet<string> anotherHashSet = new HashSet<string>(); 
foreach (var item in hashSet) 
{ 
    if (!shouldBeRemoved) 
    { 
     anotherSet.Add(item); 
    } 
} 
hashSet = anotherHashSet; 
0

Anche se non mi piace personalmente si può risolvere questo problema utilizzando un OrderedDictionary al posto di un HashSet e aggiungendo nulli come valori nella chiave/coppie di valori. Ciò consentirebbe di scorrere gli articoli per indice usando un ciclo for.

OrderedDictionary d = new OrderedDictionary; 
//Code to fill it up 
for (int i = 0;i < d.Count;i++) 
    if (shouldRemove(d[i])) 
     d.RemoveAt(i); 

Si noti che a differenza di altri tipi di dati non esiste una versione generica del OrderedDictionary a disposizione a causa del fatto che renderebbe impossibile distinguere tra accesso da indice o dalla voce nel caso in cui le chiavi sono numeri interi. Questo può portare a un sacco di casting e controllo del tipo, quindi usalo solo se le soluzioni sopra non sono un'opzione.

Problemi correlati