2009-09-26 56 views
21

Tengo un hashset en C# al que estoy eliminando si se cumple una condición mientras repito el hashset y no puedo hacer esto utilizando un bucle foreach como el siguiente.HashSet Iterando al eliminar elementos en C#

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

Entonces, ¿cómo puedo eliminar elementos durante la iteración?

Respuesta

44

Utilice el método RemoveWhere de HashSet lugar:

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

Se especifica una condición/predicado como el parámetro a el método. Cualquier elemento en el hashset que coincida con el predicado será eliminado.

Esto evita el problema de modificar el hashset mientras se está iterando.


En respuesta a tu comentario:

's' representa el elemento actual que se está evaluando desde dentro de la hashset.

El código anterior es equivalente a:

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

o:

hashset.RemoveWhere(ShouldRemove); 

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

EDIT: Algo acaba de ocurrir a mí: ya HashSet es un conjunto que no contiene ningún valores duplicados, simplemente llamando al hashset.Remove("somestring") será suficiente. No hay necesidad de hacerlo en un bucle ya que nunca habrá más de una coincidencia.

+0

Gracias, ¿qué representarían las s? – aHunter

+0

's' representa el elemento actual desde el hashset que se evalúa. Ver la respuesta actualizada. – adrianbanks

1

Por lo general, cuando quiero iterar sobre algo y quitar los valores que utilizo:

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

Gracias Sé que puedo usar un bucle for para que no pueda acceder a un HashSet usando una posición de índice de esta manera. Si estuviera usando C++, simplemente usaría punteros, no puedo hacer esto en C#. – aHunter

+0

También puede considerar el uso de una estructura de datos diferente si es posible. – Nescio

8

No se pueden eliminar elementos de una colección al tiempo que se repite con un enumerador. Dos enfoques para resolver este son:

  • bucle hacia atrás sobre la colección usando un regular indexado para bucle (que creo que no es una opción en el caso de un HashSet)
  • bucle sobre la colección, agregar elementos que ser eliminado a otra colección, a continuación, un bucle sobre la de -collection "borrar a" y eliminar los elementos:

ejemplo de la segunda aproximación:

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

El programa ya consume bastante memoria, por lo que preferiría no utilizar otra lista. Gracias – aHunter

+0

Evitaría usar dos ciclos foreach: basta un ciclo foreach, ver mi respuesta – javapowered

4

Me gustaría evitar el uso de bucle de dos foreach - un bucle foreach es suficiente:

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

Aunque no me gusta personalmente se puede resolver este problema mediante el uso de un OrderedDictionary en lugar de un HashSet y añadiendo nulos como valores en la clave/pares de valores Esto le permitiría recorrer los elementos por índice usando un bucle 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); 

Tenga en cuenta que a diferencia de otros tipos de datos no existe una versión genérica de la OrderedDictionary disponible debido al hecho de que haría imposible distinguir entre el acceso por índice o por ítem en el caso donde las claves son números enteros. Esto puede llevar a una gran cantidad de pruebas de fundición y de tipo, de modo que solo úselas si las soluciones anteriores no son una opción.

Cuestiones relacionadas