Intermediate · Collections, generics and LINQ · topic 22 of 43 · 35 min
Collections: List, Dictionary, HashSet, Queue and Stack
Explanation
Why not just arrays?
Arrays have a fixed size. Real data grows: new orders arrive, users join, items are removed. The System.Collections.Generic namespace (included by default) has collections that resize themselves. The <T> part means "of some type T": List<string> is a list of strings, List<decimal> a list of decimals.
List<T>: the everyday collection
var cart = new List<string> { "Rice", "Dal" };
cart.Add("Oil"); // Rice, Dal, Oil
cart.Insert(0, "Salt"); // Salt, Rice, Dal, Oil
cart.Remove("Dal"); // removes the first "Dal"; returns true
cart.RemoveAt(0); // removes "Salt"
Console.WriteLine(cart.Count); // 2
Console.WriteLine(cart[1]); // Oil
Console.WriteLine(cart.Contains("Rice")); // True
Console.WriteLine(string.Join(", ", cart)); // Rice, OilDictionary<TKey,TValue>: look up by key
A dictionary stores pairs: a key and its value. Give the key, get the value, almost instantly, even with a million entries. Keys must be unique.
var stock = new Dictionary<string, int>
{
["Pen"] = 120,
["Notebook"] = 45
};
stock["Eraser"] = 60; // add a new key
stock["Pen"] = 100; // replace an existing value
stock.Add("Pencil", 80); // Add throws if the key already exists
if (stock.TryGetValue("Stapler", out int qty))
Console.WriteLine(qty);
else
Console.WriteLine("Stapler not stocked");
foreach (var (item, count) in stock)
Console.WriteLine($"{item}: {count}");HashSet<T>: unique items
var visitors = new HashSet<string>();
Console.WriteLine(visitors.Add("asha@mail.com")); // True
Console.WriteLine(visitors.Add("ravi@mail.com")); // True
Console.WriteLine(visitors.Add("asha@mail.com")); // False: already there
Console.WriteLine(visitors.Count); // 2Queue<T> and Stack<T>
var tokens = new Queue<int>(); // first in, first out (FIFO)
tokens.Enqueue(101);
tokens.Enqueue(102);
tokens.Enqueue(103);
Console.WriteLine(tokens.Dequeue()); // 101: served first
Console.WriteLine(tokens.Peek()); // 102: next, not removed
var undo = new Stack<string>(); // last in, first out (LIFO)
undo.Push("typed A");
undo.Push("typed B");
Console.WriteLine(undo.Pop()); // typed B: the latest action is undone firstWhich collection should I use?
| Need | Use | Why |
|---|---|---|
| An ordered list you add to and loop over | List<T> | Simple, indexed, resizable |
| Find a value by an id, code or name | Dictionary<TKey,TValue> | Very fast lookup by key |
| Only unique values; fast "have I seen this?" | HashSet<T> | Ignores duplicates, fast Contains |
| Process in arrival order | Queue<T> | First in, first out |
| Undo, back button, nested brackets | Stack<T> | Last in, first out |
| Fixed number of items that never changes | Array | Smallest and simplest |
Speed in plain words
list.Contains(x) checks items one by one, so on a list of one lakh items it may check one lakh items. A HashSet or Dictionary jumps almost straight to the right place using the item's hash code (a number computed from the value), so the time hardly grows with size. If you search inside a loop, a Dictionary or HashSet can turn a slow program into a fast one.
Common mistakes and fixes
- Changing a list inside foreach over it: InvalidOperationException. Loop backwards with for, or use list.RemoveAll(x => ...).
- Using dict[key] for a key that may be missing: KeyNotFoundException. Use TryGetValue or ContainsKey.
- Relying on dictionary order: the order of items in a Dictionary is not guaranteed. Sort the keys if order matters.
- Using List.Contains in a big loop: switch to a HashSet.
Need help?
Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.
Try:
Watch the lesson
Collections: List, Dictionary, HashSet, Queue and Stack · 1/7
In this lesson you will use collections that grow and shrink as needed.
Prefer a video by a teacher? Find free videos on “C# List Dictionary HashSet Queue Stack collections tutorial” on YouTube ↗
In real life: Counting votes in a college election
A college in Bhubaneswar runs a class-representative election on a simple app. Each vote is a candidate name. A dictionary counts the votes, and a HashSet makes sure each roll number votes only once.
var ballots = new List<(int RollNo, string Candidate)>
{
(101, "Priya"), (102, "Arjun"), (103, "Priya"), (101, "Arjun"), (104, "Priya")
};
var voted = new HashSet<int>();
var count = new Dictionary<string, int>();
foreach (var (roll, candidate) in ballots)
{
if (!voted.Add(roll))
{
Console.WriteLine($"Roll {roll} already voted, ignored");
continue;
}
count[candidate] = count.TryGetValue(candidate, out int c) ? c + 1 : 1;
}
foreach (var (name, votes) in count)
Console.WriteLine($"{name}: {votes}");Practice (0/4 done)
var l = new List<int> { 5, 6, 7 }; l.RemoveAt(0); What is l[0]?
var q = new Queue<string>(); q.Enqueue("A"); q.Enqueue("B"); q.Enqueue("C"); q.Dequeue(); Console.WriteLine(q.Peek());
Which collection is best to check quickly if a PAN number was already registered among 10 lakh records?
Given a sentence, count how many times each word appears (ignore case) and print the words with their counts. Use a Dictionary<string, int>. Try it with "the cat and the dog and THE bird".
Quick quiz
Read more (free)
Related help
Before this, learn
This topic builds on these. If something here feels new, open them first.
Related topics
- Generics: reusable, type-safe codeCollections, generics and LINQ · same module
- LINQ basics: query data in a few linesCollections, generics and LINQ · same module
- LINQ in depth: grouping, joins, deferred execution, IQueryableCollections, generics and LINQ · same module
- HashMap and HashSetRust Programming · Error handling and collections
- set, stack, queue, deque and priority_queueC++ Programming (modern C++ and DSA) · The Standard Template Library (STL)
- Stacks and queuesPython Programming · Algorithms, data structures and testing
Questions people ask about this
Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.
What happens with dict["missing"] when the key does not exist?
Answer: KeyNotFoundException
Reading a missing key with the indexer throws. Use TryGetValue.
Which property gives the number of items in a List<T>?
Answer: Count
Collections use Count; arrays use Length.
Stack: Push(1), Push(2), Push(3), Pop(). What was returned?
Answer: 3
Last in, first out: 3.
What does HashSet<T>.Add return for a value already in the set?
Answer: false
false means nothing was added.
dict["Pen"] = 50 when "Pen" already exists...
Answer: Replaces the old value
The indexer setter adds or replaces. Add() would throw.
What does HashSet::insert return when the value is already present?Related
Which is a generic type in .NET?Related
Answer: Dictionary<TKey,TValue>
Dictionary has two type parameters.
std::priority_queue<int> pq; after pushing 4, 9 and 2, what is pq.top()?Related
Which order does a stack follow?Related
Answer: Last In, First Out
A stack is LIFO: the most recently added item is removed first.
From Stacks and queues
Pass the quiz (60% or more) or mark this topic as done when you are ready.
Your progress is saved on this device only.
Next steps
- 3 more topics in “Collections, generics and LINQ” before its exam: Generics: reusable, type-safe code, LINQ basics: query data in a few lines, LINQ in depth: grouping, joins, deferred execution, IQueryable.
- Module 6 exam: Collections, generics and LINQ · 14 questions · 25 min, without help. 4 topics of this module still to finish first.
- Then the next module, Exceptions, delegates, events and async. 43 topics left in the course before the final exam.