0Pricing
C# Academy · 课时

HashSet 与唯一性

跟踪不重复的值。

HashSet 与唯一性 是 CoddyKit 上的免费 C# Academy 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 C# Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 C# Academy 课程共包含 4 节课。

什么是 HashSet?

HashSet<T> 存储一组 unique 值,不包含重复项。添加一个已经存在的值时不会执行任何操作。

它和字典一样由哈希表支持,因此成员检查的平均时间复杂度为 O(1)。它不会保留插入顺序。

using System.Collections.Generic;

var seen = new HashSet<int>();
seen.Add(1);
seen.Add(1); // ignored, still one element

Add 返回布尔值

如果值是新的,Add 会返回 true;如果值已经存在,则返回 false。

利用这个返回值,您可以一步检测重复项,而不需要额外调用 Contains。

using System;
using System.Collections.Generic;

class Program {
    static void Main() {
        var set = new HashSet<string>();
        Console.WriteLine(set.Add("a")); // True
        Console.WriteLine(set.Add("a")); // False
    }
}

快速成员检查

对 HashSet 调用 Contains 的平均时间复杂度为 O(1),而对 List 调用时为 O(n)。

当您反复询问“我见过这个吗?”时,set 是合适的工具。随着集合变大,速度差异会显著扩大。

using System;
using System.Collections.Generic;

class Program {
    static void Main() {
        var ids = new HashSet<int> { 10, 20, 30 };
        Console.WriteLine(ids.Contains(20)); // True
        Console.WriteLine(ids.Contains(99)); // False
    }
}

从列表中移除重复项

一个常见任务是接收一个列表,只保留不重复的值。从列表构造 HashSet 就可以在 O(n) 时间内完成这件事。

结果 set 中每个值只出现一次。如果需要得到列表,请将它包装起来:new List<int>(set)。

using System;
using System.Collections.Generic;

class Program {
    static void Main() {
        var nums = new List<int> { 1, 2, 2, 3, 3, 3 };
        var unique = new HashSet<int>(nums);
        Console.WriteLine(unique.Count); // 3
    }
}

并集

UnionWith 会添加另一个集合中的每个元素,并跳过重复项。结果包含两者中的全部元素。

此操作会直接修改 set。与其自己循环并为每个项目调用 Add,这样做要简洁得多。

using System;
using System.Collections.Generic;

class Program {
    static void Main() {
        var a = new HashSet<int> { 1, 2, 3 };
        a.UnionWith(new[] { 3, 4, 5 });
        Console.WriteLine(a.Count); // 5
    }
}

交集

IntersectWith 只保留也出现在另一个集合中的元素,并移除其余元素。

您可以用它查找共同项目,例如两篇文章共享的标签,或同时出现在两个 groups 中的 users。

using System;
using System.Collections.Generic;

class Program {
    static void Main() {
        var a = new HashSet<int> { 1, 2, 3, 4 };
        a.IntersectWith(new[] { 2, 4, 6 });
        Console.WriteLine(string.Join(",", a)); // 2,4
    }
}

差集

ExceptWith 会从集合中移除另一个集合包含的所有元素,只留下该集合独有的元素。

这是集合减法运算,即“A 中有但 B 中没有的项目”。它非常适合计算发生了哪些变化,或还剩哪些内容需要处理。

var a = new HashSet<int> { 1, 2, 3, 4 };
a.ExceptWith(new[] { 2, 4 });
// a now contains 1 and 3

子集与超集

IsSubsetOf 和 IsSupersetOf 用于检查集合之间的包含关系,并返回一个 bool。

Overlaps 检查是否存在任何共享元素,SetEquals 则检查两个集合是否包含完全相同的元素,而不考虑顺序。

var a = new HashSet<int> { 1, 2 };
var b = new HashSet<int> { 1, 2, 3 };
bool sub = a.IsSubsetOf(b);   // true
bool ov = a.Overlaps(b);      // true

元素的相等性

唯一性取决于元素类型的 GetHashCode 和 Equals,这与字典键完全相同。

对于自定义类型,请重写这两个方法,或使用 record;否则,两个逻辑上相等的对象会被视为不同对象,最终都会进入 set。

var names = new HashSet<string>(
    System.StringComparer.OrdinalIgnoreCase);
names.Add("Sam");
bool dup = !names.Add("SAM"); // true: treated as same

没有索引和顺序

HashSet 不支持索引访问;您不能写出 set[0]。您只能使用 foreach 对其进行枚举。

枚举顺序不受保证。如果既需要唯一性又需要 sorted 顺序,请使用 SortedSet<T>,但要接受操作时间复杂度为 O(log n)。

using System;
using System.Collections.Generic;

class Program {
    static void Main() {
        var s = new SortedSet<int> { 3, 1, 2 };
        Console.WriteLine(string.Join(",", s)); // 1,2,3
    }
}

跟踪已见项目

一种常见模式是过滤数据流,使每个值只出现一次。请将值添加到 set 中,并且只在 Add 返回 true 时执行操作。

这比检查不断增长的列表更清晰、更快,可以将 O(n²) 的扫描转变为 O(n)。

using System;
using System.Collections.Generic;

class Program {
    static void Main() {
        var seen = new HashSet<int>();
        foreach (int x in new[] { 1, 1, 2, 3, 2 })
            if (seen.Add(x)) Console.Write(x + " ");
        // prints 1 2 3
    }
}

快速检查

请回忆 HashSet 保证的特性及其查找成本。

回顾

HashSet<T> 存储 unique 值,添加、移除和成员检查的平均时间复杂度为 O(1),但不提供顺序或索引。

它非常适合去重、快速执行“我见过这个吗”的检查,以及通过 UnionWith、IntersectWith 和 ExceptWith 进行 set 集合运算。自定义元素类型需要实现正确的相等性。

常见问题解答

「HashSet 与唯一性」课时是免费的吗?

是的 — 「HashSet 与唯一性」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 C# Academy 课程的其余内容,请升级到 CoddyKit PRO。 C# Academy 课程共包含 4 节课。

「HashSet 与唯一性」这节课中我会学到什么?

跟踪不重复的值。 你通过在浏览器中直接运行的动手代码来练习 C# Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 C# Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 C# Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。

「HashSet 与唯一性」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 C# Academy 课中编写并运行代码吗?

能。每节 C# Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 实践中的列表
  2. 字典查找
  3. HashSet 与唯一性
  4. 选择集合
← 返回 C# Academy