HashSet
A HashSet<T> holds each value once, answers "is it in here?" fast, and has no index or guaranteed order. Add tells you whether a value was new.
Journeyman · C# · Updated
After this lesson you can
- Use a HashSet<T> to keep values without duplicates, with Add, Contains and Remove
- Choose between a List<T> and a HashSet<T> for a job
Key takeaways
- A
HashSet<T>holds each value once.Addreturnstruewhen the value is new andfalsewhen it's already there. Containstells you fast whether a value is in the set, however big the set grows.- A set has no index and no guaranteed order. Loop over it with
foreach, and never depend on the order values come out. IntersectWithkeeps only the values both sets have, andUnionWithadds everything from the other set.- Use a
List<T>when order, positions or duplicates matter, and aHashSet<T>when each value should appear once.
A HashSet<T> is a collection that holds each value only once. It's the collection to reach for when the question is "have I seen this before?"
No duplicates
HashSet<string> visitors = new HashSet<string>();
Console.WriteLine(visitors.Add("Ada"));
Console.WriteLine(visitors.Add("Grace"));
Console.WriteLine(visitors.Add("Ada"));
Console.WriteLine( quot;{visitors.Count} different visitors");
Console.WriteLine(visitors.Contains("Grace"));
Console.WriteLine(visitors.Contains("Linus"));
True
True
False
2 different visitors
True
False
Add returns true when the value is new, and false when it's already there; adding it again changes nothing. Contains answers whether a value is in the set, and it answers fast, however big the set grows.
| Member | Does |
|---|---|
Add(value) |
Adds the value if it's new; returns whether it was added |
Contains(value) |
Whether the value is in the set |
Remove(value) |
Removes the value; returns whether it was there |
Count |
How many values the set holds |
No index, no order
A set has no positions: there's no visitors[0]. To see every value, loop over it with foreach. And don't count on the order: a HashSet keeps values in whatever order suits it, not the order you added them, and not sorted.
HashSet<int> seatsSold = new HashSet<int> { 14, 3, 9 };
seatsSold.Add(3);
seatsSold.Remove(9);
Console.WriteLine( quot;{seatsSold.Count} seats sold");
foreach (int seat in seatsSold)
{
Console.WriteLine( quot;Seat {seat} is taken");
}
2 seats sold
Seat 14 is taken
Seat 3 is taken
(The loop happened to print 14 before 3. Code that depends on a set's order is a bug waiting to happen.)
Two sets together
Sets can be combined. IntersectWith keeps only what both sets have, and UnionWith adds everything from the other set:
HashSet<string> adaKnows = new HashSet<string> { "C#", "SQL", "HTML" };
HashSet<string> jobNeeds = new HashSet<string> { "C#", "SQL", "Angular" };
HashSet<string> matches = new HashSet<string>(adaKnows);
matches.IntersectWith(jobNeeds);
Console.WriteLine( quot;Matching skills: {matches.Count}");
Console.WriteLine(matches.Contains("Angular"));
Matching skills: 2
False
new HashSet<string>(adaKnows) makes a copy first, so adaKnows itself isn't changed.
List or HashSet?
Use a List<T> when |
Use a HashSet<T> when |
|---|---|
| The order matters | Only "is it in there?" matters |
| Duplicates are allowed, or meaningful | Each value should appear once |
You need items by position: list[0] |
You check Contains often, on many values |
| Example: the items on an order, in order | Example: the seats already sold, the tags on a post |
Check yourself
2 questions to try on the lesson page.
So what
When duplicates would be a bug, a HashSet makes them impossible, and it answers "is this one taken?" instantly. Seats, tags, usernames, visited pages: anything that should appear once belongs in a set.