C# HashSet

A HashSet<T> is a collection that stores unique items only. It automatically rejects duplicates. It also provides blazing-fast lookups — checking whether an item exists is nearly instant regardless of how many items are stored.

What Makes HashSet Special?

┌────────────────────────────────────────────────────────────────┐
│                 LIST vs HASHSET                                │
├──────────────────────────────┬─────────────────────────────────┤
│ List<T>                      │ HashSet<T>                      │
├──────────────────────────────┼─────────────────────────────────┤
│ Allows duplicates            │ No duplicates allowed           │
├──────────────────────────────┼─────────────────────────────────┤
│ Preserves insertion order    │ No guaranteed order             │
├──────────────────────────────┼─────────────────────────────────┤
│ Contains() scans all items   │ Contains() is near-instant (O1) │
├──────────────────────────────┼─────────────────────────────────┤
│ General purpose              │ Uniqueness and fast lookup      │
└──────────────────────────────┴─────────────────────────────────┘

Real-World Analogy

┌────────────────────────────────────────────────────────────┐
│  HashSet = Guest List at an event                          │
├────────────────────────────────────────────────────────────┤
│  ✅ "Alice" added → on the list                            │
│  ✅ "Bob" added   → on the list                            │
│  ❌ "Alice" added → already on list, ignored               │
│                                                            │
│  The bouncer (HashSet) never lets the same person in twice │
└────────────────────────────────────────────────────────────┘

Creating a HashSet

using System;
using System.Collections.Generic;

HashSet<int> numbers = new HashSet<int>();

HashSet<string> names = new HashSet<string>() { "Alice", "Bob", "Carol" };

Adding Items

Add() returns true if the item was added, or false if it already existed.

HashSet<string> tags = new HashSet<string>();

Console.WriteLine(tags.Add("csharp"));  // True  — added
Console.WriteLine(tags.Add("dotnet"));  // True  — added
Console.WriteLine(tags.Add("csharp"));  // False — already exists

Console.WriteLine(tags.Count);  // 2
// HashSet contains: { "csharp", "dotnet" }

Add Diagram

┌────────────────────────────────────────────────────────────┐
│   Add("A") → hash("A") → bucket 3 → stored                 │
│   Add("B") → hash("B") → bucket 7 → stored                 │
│   Add("A") → hash("A") → bucket 3 → ALREADY EXISTS → skip  │
└────────────────────────────────────────────────────────────┘

Checking Membership

HashSet<int> primes = new HashSet<int>() { 2, 3, 5, 7, 11, 13 };

Console.WriteLine(primes.Contains(7));   // True
Console.WriteLine(primes.Contains(6));   // False

// This lookup is O(1) — same speed with 10 or 10 million items

Removing Items

HashSet<string> fruits = new HashSet<string>() { "Apple", "Mango", "Banana" };

fruits.Remove("Mango");
Console.WriteLine(fruits.Contains("Mango"));  // False
Console.WriteLine(fruits.Count);              // 2

fruits.Clear();
Console.WriteLine(fruits.Count);              // 0

Set Operations

HashSet supports mathematical set operations: union, intersection, and difference. These are powerful for comparing two groups of data.

Union — Combine Two Sets

HashSet<int> setA = new HashSet<int>() { 1, 2, 3, 4 };
HashSet<int> setB = new HashSet<int>() { 3, 4, 5, 6 };

setA.UnionWith(setB);
// setA = { 1, 2, 3, 4, 5, 6 } — all unique items from both sets

// Diagram:
// A = { 1, 2, 3, 4 }
// B = {       3, 4, 5, 6 }
//     ──────────────────
// A∪B = { 1, 2, 3, 4, 5, 6 }

Intersection — Common Items Only

HashSet<int> setA = new HashSet<int>() { 1, 2, 3, 4 };
HashSet<int> setB = new HashSet<int>() { 3, 4, 5, 6 };

setA.IntersectWith(setB);
// setA = { 3, 4 } — only items in both sets

// Diagram:
// A = { 1, 2, [3, 4] }
// B = {       [3, 4], 5, 6 }
//     ─────────────────
// A∩B = { 3, 4 }

Difference — Items in A but NOT in B

HashSet<int> setA = new HashSet<int>() { 1, 2, 3, 4 };
HashSet<int> setB = new HashSet<int>() { 3, 4, 5, 6 };

setA.ExceptWith(setB);
// setA = { 1, 2 } — items in A that are NOT in B

// Diagram:
// A = { [1, 2], 3, 4 }
// B = {         3, 4, 5, 6 }
//     ─────────────────
// A-B = { 1, 2 }

Symmetric Difference — Items in Either, Not Both

HashSet<int> setA = new HashSet<int>() { 1, 2, 3, 4 };
HashSet<int> setB = new HashSet<int>() { 3, 4, 5, 6 };

setA.SymmetricExceptWith(setB);
// setA = { 1, 2, 5, 6 } — items in one but NOT both

// Diagram:
// A = { [1, 2], 3, 4 }
// B = {         3, 4, [5, 6] }
//              shared = removed
// Result = { 1, 2, 5, 6 }

Set Comparison Methods

HashSet<int> a = new HashSet<int>() { 1, 2, 3 };
HashSet<int> b = new HashSet<int>() { 1, 2, 3, 4, 5 };
HashSet<int> c = new HashSet<int>() { 1, 2, 3 };

Console.WriteLine(a.IsSubsetOf(b));       // True  — all of a is in b
Console.WriteLine(b.IsSupersetOf(a));     // True  — b contains all of a
Console.WriteLine(a.SetEquals(c));        // True  — same items
Console.WriteLine(a.Overlaps(b));         // True  — at least one common item

Real Example: Remove Duplicates from a List

List<int> withDuplicates = new List<int>() { 5, 3, 8, 3, 1, 5, 9, 8 };

// Convert to HashSet removes all duplicates instantly:
HashSet<int> unique = new HashSet<int>(withDuplicates);

Console.WriteLine(string.Join(", ", unique));
// Output: 5, 3, 8, 1, 9  (order may vary)

// Or convert back to List:
List<int> cleanList = new List<int>(unique);

Iterating Through a HashSet

HashSet<string> cities = new HashSet<string>() { "London", "Tokyo", "Paris" };

foreach (string city in cities)
{
    Console.WriteLine(city);
}
// Order is NOT guaranteed

Quick Method Reference

┌──────────────────────────────┬──────────────────────────────────┐
│ Method                       │ What It Does                     │
├──────────────────────────────┼──────────────────────────────────┤
│ Add(item)                    │ Add item (returns bool)          │
│ Remove(item)                 │ Remove item                      │
│ Contains(item)               │ Fast membership check            │
│ Clear()                      │ Remove all items                 │
│ Count                        │ Number of items                  │
│ UnionWith(other)             │ Add all from other set           │
│ IntersectWith(other)         │ Keep only common items           │
│ ExceptWith(other)            │ Remove items found in other      │
│ SymmetricExceptWith(other)   │ Keep non-shared items            │
│ IsSubsetOf(other)            │ All my items in other?           │
│ IsSupersetOf(other)          │ All other items in me?           │
│ SetEquals(other)             │ Exact same items?                │
│ Overlaps(other)              │ Any items in common?             │
└──────────────────────────────┴──────────────────────────────────┘

HashSet is the right collection when uniqueness and fast lookup matter more than order. It powers features like visited-URL tracking in browsers, user tag systems, permission checks, and any scenario where you need to answer "is this item already here?" as fast as possible.

Leave a Comment

Your email address will not be published. Required fields are marked *