Подтвердить что ты не робот

HashSet Итерация при удалении элементов в С#

У меня есть hashset в С#, который я удаляю, если условие выполняется во время итерации, хотя hashset и не может сделать это, используя цикл foreach, как показано ниже.

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

Итак, как я могу удалить элементы во время итерации?

4b9b3361

Ответ 1

Используйте RemoveWhere метод HashSet:

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

Вы указываете условие/предикат как параметр метода. Любой элемент в hashset, который соответствует предикату, будет удален.

Это позволяет избежать проблемы изменения хешета во время его повторения.


В ответ на ваш комментарий:

's' представляет текущий элемент, оцениваемый из хэш-набора.

Вышеприведенный код эквивалентен:

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

или

hashset.RemoveWhere(ShouldRemove);

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

EDIT: Что-то мне пришло в голову: поскольку HashSet - это набор, который не содержит повторяющихся значений, достаточно просто вызвать hashset.Remove("somestring"). Нет необходимости делать это в цикле, поскольку никогда не будет больше одного совпадения.

Ответ 2

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

  • Прокрутите назад по коллекции с помощью регулярного индексированного цикла for (который, я считаю, не является опцией в случае HashSet)
  • Прокрутите коллекцию, добавьте элементы, которые нужно удалить, в другую коллекцию, затем зациклируйте "to-be-deleted" -collection и удалите элементы:

Пример второго подхода:

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);
}

Ответ 3

Я бы не использовал два цикла foreach - достаточно одного цикла foreach:

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

Ответ 4

Обычно, когда я хочу перебрать что-то и удалить значения, которые я использую:

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

Ответ 5

Хотя мне это не нравится, вы можете решить эту проблему, используя OrderedDictionary вместо HashSet и добавляя нули в качестве значений в парах ключ/значение. Это позволит вам перебирать элементы по индексу с помощью цикла 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);

Обратите внимание, что в отличие от других типов данных не существует общей версии доступной OrderedDictionary из-за того, что она не позволяет отличить доступ по индексу или по элементу в случае, когда ключи являются целыми числами. Это может привести к многократной проверке и проверке типов, поэтому используйте его только в том случае, если вышеуказанные решения не являются вариантом.