HashSet Итерация при удалении элементов в С#
У меня есть hashset в С#, который я удаляю, если условие выполняется во время итерации, хотя hashset и не может сделать это, используя цикл foreach, как показано ниже.
foreach (String hashVal in hashset)
{
if (hashVal == "somestring")
{
hash.Remove("somestring");
}
}
Итак, как я могу удалить элементы во время итерации?
Ответы
Ответ 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 из-за того, что она не позволяет отличить доступ по индексу или по элементу в случае, когда ключи являются целыми числами. Это может привести к многократной проверке и проверке типов, поэтому используйте его только в том случае, если вышеуказанные решения не являются вариантом.