C# Programming Tutorial 0/45 lessons ~6 min read Lesson 24

    HashSet

    HashSet<T> stores unique elements with O(1) Contains — ideal for deduplication, visited tracking, and set algebra (Union, Intersect, Except).

    Course progress0%
    Focus
    10 guided sections
    Practice signal
    Examples included
    Career prep
    Interview Q&A included

    Introduction

    HashSet<T> stores unique elements with O(1) Contains — ideal for deduplication, visited tracking, and set algebra (Union, Intersect, Except). Unlike Dictionary, no value payload — only keys in a set semantics.

    Interview graph problems use HashSet for cycle detection. Enterprise apps use HashSet for permission sets and tag collections.

    The story

    An enterprise admin portal checks whether a user holds all permissions required to approve a payroll run. Permissions are stored in a case-insensitive set for O(1) lookups, and auditors sometimes need to see which permissions two roles share — a set intersection operation.

    Understanding the topic

    Key concepts

    • Uniqueness enforced on Add.
    • Add returns false if duplicate.
    • Set operations: UnionWith, IntersectWith, ExceptWith.
    • No indexing — enumeration order undefined.
    • Hash-based like Dictionary without values.
    • FrozenSet for immutable read-heavy (.NET 8).

    Step-by-step explanation

    1. Add inserts if not present.
    2. Contains checks membership O(1) average.
    3. Remove deletes element.
    4. Set operations modify in place or LINQ ToHashSet.
    5. ExceptWith removes elements in other set.
    6. Comparer optional for custom equality.

    Practical code example

    Permission checker with HashSet and set intersection:

    csharp
    namespace TechLearningPro.HashSet;
    public sealed class PermissionService
    {
    private readonly HashSet<string> _userPermissions;
    public PermissionService(IEnumerable<string> permissions) =>
    _userPermissions = permissions.ToHashSet(StringComparer.OrdinalIgnoreCase);
    public bool HasAll(IEnumerable<string> required) =>
    required.All(p => _userPermissions.Contains(p));
    public HashSet<string> CommonWith(IEnumerable<string> other) =>
    _userPermissions.Intersect(other, StringComparer.OrdinalIgnoreCase).ToHashSet(StringComparer.OrdinalIgnoreCase);
    }

    Line-by-line code explanation

    • HashSet<string> _userPermissions stores unique permission strings with fast membership tests.
    • permissions.ToHashSet(StringComparer.OrdinalIgnoreCase) builds the set ignoring case differences.
    • HasAll(IEnumerable<string> required) checks that every required permission is present.
    • required.All(p => _userPermissions.Contains(p)) uses LINQ with O(1) Contains per permission.
    • CommonWith(IEnumerable<string> other) finds permissions shared with another collection.
    • _userPermissions.Intersect(other, StringComparer.OrdinalIgnoreCase) computes the set intersection.
    • .ToHashSet(StringComparer.OrdinalIgnoreCase) materializes the result as a new case-insensitive set.

    Key takeaway: StringComparer.OrdinalIgnoreCase for case-insensitive permissions. Intersect returns shared permissions — useful for audit UI.

    Real-world use

    Where you'll use this in production

    • RBAC permission checks.
    • Deduplicating email recipient lists.
    • Graph visited nodes in BFS/DFS.
    • Tag filtering on product catalogs.

    Best practices

    • Use HashSet when need uniqueness + fast Contains.
    • Specify StringComparer for case rules.
    • ToHashSet() materializes LINQ distinct efficiently.
    • FrozenSet when set never changes after build.
    • Prefer over List for membership-heavy loops.

    Common mistakes

    • Using List.Contains in loop — O(n²).
    • Assuming stable iteration order.
    • Forgetting comparer — case sensitivity bugs.
    • Mutating elements affecting hash after Add.

    Advanced interview questions

    Q1BeginnerHashSet vs List?
    HashSet unique O(1) Contains; List allows duplicates O(n) Contains.
    Q2BeginnerAdd return value meaning?
    true if added; false if duplicate already present.
    Q3IntermediateDetect cycle in linked list?
    Floyd tortoise-hare or HashSet of visited nodes.
    Q4IntermediateUnion vs Concat?
    Union distinct merge; Concat preserves duplicates.
    Q5AdvancedFind duplicate in stream of 1M ints memory-efficient?
    If range small use bit array; else HashSet; if sorted use sort+scan O(1) extra if range bounded.

    Summary

    HashSet enforces uniqueness with fast membership tests. Set algebra operations simplify permission and tag logic. Replace List.Contains hot paths with HashSet. FrozenSet optimizes immutable read scenarios. Next: Queue and Stack FIFO/LIFO structures.

    Ready to mark this lesson complete?Track your journey across the entire course.