HashSet 在 C# 中删除项目时进行迭代

问题描述 投票:0回答:7

我在 C# 中有一个哈希集,如果在迭代哈希集时满足条件,我将从中删除该哈希集,并且无法使用 foreach 循环来执行此操作,如下所示。

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

那么,如何在迭代时删除元素?

c# hashset
7个回答
59
投票

使用 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")
就足够了。无需循环执行,因为永远不会有超过一个匹配。


10
投票

使用枚举器循环遍历集合时,无法从集合中删除项目。解决这个问题的两种方法是:

  • 使用常规索引 for 循环向后循环集合(我认为在
    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);
}

9
投票

我会避免使用两个 foreach 循环 - 一个 foreach 循环就足够了:

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

0
投票

对于那些正在寻找一种方法来处理 HashSet 中的元素并删除它们的人,我按照以下方式进行了

var set = new HashSet<int> {1, 2, 3};

while (set.Count > 0)
{
  var element = set.FirstOrDefault();
  Process(element);
  set.Remove(element);
}

0
投票

这里有一个更简单的解决方案。

var mySet = new HashSet<string>();
foreach(var val in mySet.ToArray() {
   Console.WriteLine(val);
   mySet.Remove(val);
}

.ToArray() 已经为您创建了一个副本。您可以循环播放您喜欢的内容。


0
投票

我在Unity上用不同的方法做了一些性能测试(所以它在其他框架上的工作方式不同)。

处理 500k 项的时间

测试方法:

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

-1
投票

通常当我想迭代某些内容并删除我使用的值时:

 For (index = last to first)
      If(ShouldRemove(index)) Then
           Remove(index)
© www.soinside.com 2019 - 2024. All rights reserved.