How to use HashSet in C#

By FoxLearn 1/6/2025 7:18:34 AM   67
The HashSet is a high-performance collection used for storing unique, unordered elements, designed to speed up search operations in applications.

It provides fast lookups and efficient set operations. Introduced in .NET 3.5, it is part of the System.Collections.Generic namespace.

What is a HashSet?

A HashSet, represented by the HashSet class in the System.Collections.Generic namespace, is a high-performance, unordered collection of unique elements. It doesn't support sorting, duplicate elements, or indexing, and is typically used for efficient operations involving unique data.

HashSet stores only unique elements and is optimized for faster searches. It allows a single null value and is ideal for collections that require uniqueness and quick search performance.

Searching Items in a HashSet in C#

Here's an example of searching an item in a HashSet using the Contains method:

static void Main(string[] args)
{
    HashSet<int> numbers = new HashSet<int>();
    numbers.Add(10);
    numbers.Add(20);
    numbers.Add(30);
    numbers.Add(40);
    
    if (numbers.Contains(30))
        Console.WriteLine("The number is found in the set.");
    else
        Console.WriteLine("The number is not found in the set.");
    
    Console.ReadKey();
}

HashSet elements are always unique

Here’s an example demonstrating that attempting to insert a duplicate element in a HashSet is ignored without throwing a runtime exception:

static void Main(string[] args)
{
    HashSet<int> numbers = new HashSet<int>();
    numbers.Add(10);
    numbers.Add(20);
    numbers.Add(30);
    numbers.Add(40);
    numbers.Add(30);  // Duplicate element
    
    Console.WriteLine("The number of elements in the set is: {0}", numbers.Count);
    Console.ReadKey();
}

In this example, the attempt to add a duplicate element (30) is ignored, and no exception is thrown. The count of elements will remain unaffected by the duplicate.

Here’s another example demonstrating how duplicate elements are eliminated when added to a HashSet:

static void Main(string[] args)
{
    string[] countries = new string[] {
        "USA",
        "India",
        "Canada",
        "Australia",
        "India",
        "UK"
    };
    
    HashSet<string> hashSet = new HashSet<string>(countries);
    
    foreach (var country in hashSet)
    {
        Console.WriteLine(country);
    }
}

In this example, when the array of countries is passed to the HashSet, the duplicate entry "India" will be removed, and only unique countries will be printed.

Removing Elements from a HashSet in C#

Here's another example demonstrating how to remove an item from a HashSet using the Remove method:

static void Main(string[] args)
{
    HashSet<int> numbers = new HashSet<int> { 10, 20, 30, 40, 50 };
    int numberToRemove = 30;

    if (numbers.Contains(numberToRemove))
    {
        numbers.Remove(numberToRemove);
        Console.WriteLine($"{numberToRemove} has been removed.");
    }
    else
    {
        Console.WriteLine($"{numberToRemove} is not in the set.");
    }

    Console.ReadKey();
}

In this example, the Remove method is used to remove the number 30 from the HashSet. If the item exists, it will be removed, otherwise, a message indicating it wasn't found will be displayed. Additionally, to remove all elements from a HashSet, you can use the Clear method.

Using HashSet set operations methods in C#

Here’s an example demonstrating some important set operations provided by the HashSet class in C#, such as IsProperSubsetOf, UnionWith, IntersectWith, ExceptWith, and SymmetricExceptWith:

1. IsProperSubsetOf

The IsProperSubsetOf method checks if a HashSet is a proper subset of another collection.

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

if (setA.IsProperSubsetOf(setB))
    Console.WriteLine("setA is a proper subset of setB.");

if (!setA.IsProperSubsetOf(setC))
    Console.WriteLine("setA is not a proper subset of setC.");

In this example, the output will be:

setA is a proper subset of setB.
setA is not a proper subset of setC.

2. UnionWith

The UnionWith method adds elements from another collection to the current HashSet, combining them while removing duplicates:

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

setA.UnionWith(setB);

foreach (var number in setA)
{
    Console.WriteLine(number);
}

This will output:

1
2
3
4
5
6

The elements of setB are added to setA, but duplicates are avoided.

3. IntersectWith

The IntersectWith method modifies the current HashSet to keep only the elements that exist in both HashSets (the intersection):

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

setA.IntersectWith(setB);

foreach (var number in setA)
{
    Console.WriteLine(number);
}

The output will be:

3
4
5

Only the common elements between setA and setB remain.

4. ExceptWith

The ExceptWith method removes elements from the current HashSet that are present in another collection (set subtraction):

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

setA.ExceptWith(setB);

foreach (var number in setA)
{
    Console.WriteLine(number);
}

The output will be:

1
2
5

The elements 3 and 4 are removed from setA because they are in setB.

6. SymmetricExceptWith

The SymmetricExceptWith method modifies the HashSet to contain only the elements that are unique to each set (elements that are not in both sets):

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

setA.SymmetricExceptWith(setB);

foreach (var number in setA)
{
    Console.WriteLine(number);
}

The output will be:

1
2
3
6
7

Only the elements that are unique to each set (1, 2, 3, 6, 7) remain.

Accessing an element in a HashSet has an average time complexity of O(1), making it ideal for fast searches and set operations. In contrast, accessing an element in an array has a time complexity of O(n). If you need to store items in a specific order or allow duplicates, a List is a better choice.