我在 C# 中有一个哈希集,如果在迭代哈希集时满足条件,我将从中删除该哈希集,并且无法使用 foreach 循环来执行此操作,如下所示。
foreach (String hashVal in hashset)
{
if (hashVal == "somestring")
{
hash.Remove("somestring");
}
}
那么,如何在迭代时删除元素?
使用 HashSet 的 RemoveWhere 方法来代替:
hashset.RemoveWhere(s => s == "somestring");
您指定一个条件/谓词作为方法的参数。哈希集中与谓词匹配的任何项目都将被删除。
这避免了在迭代时修改哈希集的问题。
回复您的评论:
's' 表示从哈希集中评估当前项目。
上面的代码相当于:
hashset.RemoveWhere(delegate(string s) {return s == "somestring";});
或:
hashset.RemoveWhere(ShouldRemove);
public bool ShouldRemove(string s)
{
return s == "somestring";
}
编辑: 我突然想到一件事:由于 HashSet 是一个不包含重复值的集合,因此只需调用
hashset.Remove("somestring")
就足够了。无需循环执行,因为永远不会有超过一个匹配。
使用枚举器循环遍历集合时,无法从集合中删除项目。解决这个问题的两种方法是:
HashSet
的情况下这不是一个选项)第二种方法的示例:
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);
}
我会避免使用两个 foreach 循环 - 一个 foreach 循环就足够了:
HashSet<string> anotherHashSet = new HashSet<string>();
foreach (var item in hashSet)
{
if (!shouldBeRemoved)
{
anotherSet.Add(item);
}
}
hashSet = anotherHashSet;
对于那些正在寻找一种方法来处理 HashSet 中的元素并删除它们的人,我按照以下方式进行了
var set = new HashSet<int> {1, 2, 3};
while (set.Count > 0)
{
var element = set.FirstOrDefault();
Process(element);
set.Remove(element);
}
这里有一个更简单的解决方案。
var mySet = new HashSet<string>();
foreach(var val in mySet.ToArray() {
Console.WriteLine(val);
mySet.Remove(val);
}
.ToArray() 已经为您创建了一个副本。您可以循环播放您喜欢的内容。
我在Unity上用不同的方法做了一些性能测试(所以它在其他框架上的工作方式不同)。
处理 500k 项的时间
int
上约为 20 毫秒,Test
类上约为 50 毫秒)int
上约 2 毫秒,Test
类约 2 毫秒)int
上约 19 毫秒,Test
类上约 30 毫秒)int
上约 5 毫秒,Test
课程约 5 毫秒)测试方法:
private void Test() {
Debug.Log("Start Test");
HashSet<Test> hashSet = new();
for (int i = 0; i < 500000; i++) {
hashSet.Add(new Test(i));
}
HashSet<Test> testSet = new(hashSet);
Stopwatch sw = new();
sw.Start();
foreach (Test test in testSet.ToList()) {
if (test.A % 2 == 0) hashSet.Remove(test);
}
sw.Stop();
Debug.Log("1 " + sw.ElapsedMilliseconds);
testSet = new HashSet<Test>(hashSet);
sw.Reset();
sw.Start();
testSet.RemoveWhere(test => test.A % 2 == 0);
sw.Stop();
Debug.Log("2 " + sw.ElapsedMilliseconds);
testSet = new HashSet<Test>(hashSet);
sw.Reset();
sw.Start();
HashSet<Test> toKeep = new();
foreach (Test test in testSet) {
if (test.A % 2 != 0) toKeep.Add(test);
}
testSet = toKeep;
sw.Stop();
Debug.Log("3 " + sw.ElapsedMilliseconds);
testSet = new HashSet<Test>(hashSet);
sw.Reset();
sw.Start();
HashSet<Test> toRemove = new();
foreach (Test test in testSet) {
if (test.A % 2 == 0) toRemove.Add(test);
}
foreach (Test test in toRemove) {
testSet.Remove(test);
}
sw.Stop();
Debug.Log("4 " + sw.ElapsedMilliseconds);
}
测试班:
public class Test {
public int A;
public Test(int a) {
A = a;
}
}
通常当我想迭代某些内容并删除我使用的值时:
For (index = last to first)
If(ShouldRemove(index)) Then
Remove(index)