HashSet<T> and choosing the right shape
Uniqueness and set math, plus a decision table for List, Dictionary, and HashSet.
One of each, no order
var seen = new HashSet<string>();
seen.Add("a"); // True โ new
bool dup = seen.Add("a"); // False โ already there
Console.WriteLine(seen.Count); // 1
Add returns whether anything changed โ a one-call duplicate check. Contains is O(1) (hash-based), unlike List.Contains's O(n) scan. Set math is built in: seen.UnionWith(other), IntersectWith, ExceptWith mutate the set; Overlaps/IsSubsetOf answer questions.
The dedup-and-count pair
var distinct = new HashSet<string>(words); // copies + dedups
Console.WriteLine(distinct.Count); // number of unique words
Constructing from an existing collection is the fastest dedup in the language โ and combining a HashSet (uniqueness) with a Dictionary (counts) covers frequency tables.
Choosing the shape
| Need | Shape |
| --- | --- |
| Ordered values, duplicates OK, index access | List<T> |
| Unique values, fast membership | HashSet<T> |
| Look up by a key | Dictionary<TKey,TValue> |
| Fixed size, index access | array |
The wrong shape forces manual workarounds โ deduping a List by hand, or searching a Dictionary's Values. Decide from the operations you need, not habit: "do I need duplicates? do I need positions? do I need keys?" Those three questions pick the container in almost every beginner program.