Syntax
HashSet<Type> set = new HashSet<Type>();Examples
Creating a HashSet and Adding Elements
Duplicates are automatically ignored.
HashSet<string> tags = new HashSet<string>();
tags.Add("csharp");
tags.Add("dotnet");
tags.Add("csharp"); // duplicate - ignored, Add() returns false
Console.WriteLine(string.Join(", ", tags)); // csharp, dotnet
Console.WriteLine(tags.Count); // 2Checking Membership
HashSet provides very fast membership testing, much faster than searching a List<T>.
HashSet<int> validIds = new HashSet<int> { 101, 102, 103 };
Console.WriteLine(validIds.Contains(102)); // true
Console.WriteLine(validIds.Contains(999)); // falseSet Operations
Union, intersection, and difference using built-in methods.
HashSet<int> a = new HashSet<int> { 1, 2, 3, 4 };
HashSet<int> b = new HashSet<int> { 3, 4, 5, 6 };
HashSet<int> union = new HashSet<int>(a);
union.UnionWith(b);
Console.WriteLine(string.Join(", ", union)); // 1, 2, 3, 4, 5, 6
HashSet<int> intersection = new HashSet<int>(a);
intersection.IntersectWith(b);
Console.WriteLine(string.Join(", ", intersection)); // 3, 4
HashSet<int> difference = new HashSet<int>(a);
difference.ExceptWith(b);
Console.WriteLine(string.Join(", ", difference)); // 1, 2Removing Duplicates from a List
A very common practical use of HashSet<T>.
List<string> namesWithDupes = new List<string> { "Fola", "Zain", "Fola", "Jamal" };
HashSet<string> uniqueNames = new HashSet<string>(namesWithDupes);
Console.WriteLine(string.Join(", ", uniqueNames)); // Fola, Zain, JamalBest practices
- Use HashSet<T> when you need fast membership testing (Contains()) or automatic deduplication and do not care about element order
- Use a SortedSet<T> instead if you need elements kept in sorted order, since HashSet makes no ordering guarantee
- Always override Equals() and GetHashCode() properly (or use a record) for any custom class stored in a HashSet, or duplicate detection will not work correctly
- Prefer a HashSet<T> over a List<T> for repeated Contains() checks on large collections - it is dramatically faster
At a glance
- Purpose
- Applications on the .NET platform
- File extension
- .cs
- Runs in
- .NET runtime
- Usually used with
- .NET SDK and libraries
Specifications & further reading
Related C# documentation
List<T>
List<T> is a resizable, generic collection from System.Collections.Generic, and the most commonly used collection type in C#. Unlike a plain array, a List<T> automatically grows as elements are added, and it provides a rich set of methods for adding, removing, searching, and sorting. The <T> means a List can be strongly typed to hold any specific type, like List<string> or List<int>.Dictionary<TKey, TValue>
Dictionary<TKey, TValue> stores data as key-value pairs, offering fast average-case lookup, insertion, and deletion by key, backed by a hash table. Keys must be unique - adding a value with an existing key throws an exception, while indexer assignment (dict[key] = value) overwrites it instead. Dictionary does not guarantee any particular iteration order.Queue<T> & Stack<T>
Queue<T> is a first-in-first-out (FIFO) collection - items are added with Enqueue() and removed with Dequeue(), just like a real-world line. Stack<T> is last-in-first-out (LIFO) - items are added with Push() and removed with Pop(), like a stack of plates. Both are useful for specific processing orders where a general-purpose List<T> would require extra bookkeeping.foreach & IEnumerable
foreach is C#'s dedicated loop for iterating over any collection that implements IEnumerable<T> - which includes arrays, List<T>, Dictionary<TKey,TValue>, and virtually every built-in collection. Behind the scenes, foreach uses an enumerator (via GetEnumerator()) to walk through items one at a time. Any custom class can support foreach by implementing IEnumerable<T> itself.
List<T> is a resizable, generic collection from System.Collections.Generic, and the most commonly used collection type in C#. Unlike a plain array, a List<T> automatically grows as elements are added, and it provides a rich set of methods for adding, removing, searching, and sorting. The <T> means a List can be strongly typed to hold any specific type, like List<string> or List<int>.Dictionary<TKey, TValue>
Dictionary<TKey, TValue> stores data as key-value pairs, offering fast average-case lookup, insertion, and deletion by key, backed by a hash table. Keys must be unique - adding a value with an existing key throws an exception, while indexer assignment (dict[key] = value) overwrites it instead. Dictionary does not guarantee any particular iteration order.Queue<T> & Stack<T>
Queue<T> is a first-in-first-out (FIFO) collection - items are added with Enqueue() and removed with Dequeue(), just like a real-world line. Stack<T> is last-in-first-out (LIFO) - items are added with Push() and removed with Pop(), like a stack of plates. Both are useful for specific processing orders where a general-purpose List<T> would require extra bookkeeping.foreach & IEnumerable
foreach is C#'s dedicated loop for iterating over any collection that implements IEnumerable<T> - which includes arrays, List<T>, Dictionary<TKey,TValue>, and virtually every built-in collection. Behind the scenes, foreach uses an enumerator (via GetEnumerator()) to walk through items one at a time. Any custom class can support foreach by implementing IEnumerable<T> itself.