Collections

16 questions found

When would you use a List<T> vs an array?

Beginner
Use an array for a fixed-size, performance-critical buffer; use List<T> when the count changes, since it grows and offers Add/Remove/Insert.
int[] fixedGrid = new int[9];
var items = new List<string>(); items.Add("a");
Real-world example A game board is an array; a shopping cart is a List<T>.

When should you use a Dictionary<TKey,TValue>?

Beginner
When you need fast key-based lookups (O(1) average). Keys are unique; use TryGetValue to avoid exceptions on missing keys.
var prices = new Dictionary<string,decimal>{["pen"]=1.5m};
if (prices.TryGetValue("pen", out var p)) { }
Real-world example Caching users by Id or counting word frequencies.

What is the difference between IEnumerable, ICollection and IList?

Intermediate
IEnumerable supports iteration only; ICollection adds Count/Add/Remove; IList adds indexed access and Insert. Accept the least specific type your method needs.
void Print(IEnumerable<int> xs) {}
int First(IList<int> xs) => xs[0];
Real-world example Accepting IEnumerable<T> in APIs keeps callers flexible (arrays, lists, LINQ).

What does HashSet<T> provide and when do you use it?

Intermediate
A set of unique elements with fast Contains/Add and set operations. Adding a duplicate is a no-op.
var seen = new HashSet<int>();
if (!seen.Add(id)) Console.WriteLine("duplicate");
Real-world example De-duplicating ids or checking membership in a loop without O(n) scans.

When would you reach for a ConcurrentDictionary or an immutable collection?

Advanced
Use ConcurrentDictionary for thread-safe reads/writes without external locks; use ImmutableList/Dictionary when you want safe sharing across threads via copy-on-write snapshots.
var cache = new ConcurrentDictionary<int,User>();
cache.GetOrAdd(id, Load);
Real-world example A shared in-memory cache updated by many request threads uses ConcurrentDictionary.

How do you avoid multiple enumeration of an IEnumerable?

Advanced
Deferred sequences re-run their query each time you enumerate them; materialise once with ToList()/ToArray() if you iterate more than once or the source is expensive.
var q = Load().Where(x => x.Active);
var list = q.ToList(); // enumerate once
var count = list.Count; foreach (var x in list) {}
Real-world example Enumerating a database-backed IQueryable twice issues two SQL queries — materialise first.

What is the difference between List<T> and an array (T[]) in terms of resizing?

Beginner
An array has a FIXED size determined at creation and can never grow or shrink; List<T> is a dynamically-resizable collection built on top of an internal array that automatically grows (by reallocating and copying to a larger array) as you add elements beyond its current capacity.
int[] fixedArray = new int[3]; // always exactly 3 elements
// fixedArray[3] = 4; // IndexOutOfRangeException

List<int> list = new List<int>();
list.Add(1); list.Add(2); list.Add(3); list.Add(4); // grows automatically
Real-world example Using List<T> for a shopping cart's items (unknown count ahead of time) versus a fixed array for exactly 7 days of the week.

Common follow-ups: What happens internally when a List<T>'s capacity is exceeded and it needs to grow?

Arrays Span<T> & Memory<T>

What is the difference between Dictionary<TKey, TValue> and List<T> in terms of lookup performance?

Beginner
Dictionary<TKey, TValue> provides average O(1) constant-time lookups by key via hashing; List<T> requires an O(n) linear scan to find an element unless you already know its exact index — Dictionary is the right choice whenever you need fast lookups by a unique identifier.
Dictionary<string, int> ages = new() { ["Sam"] = 30, ["Alex"] = 25 };
int samAge = ages["Sam"]; // O(1) lookup

List<(string Name, int Age)> list = new() { ("Sam", 30), ("Alex", 25) };
int samAge2 = list.First(p => p.Name == "Sam").Age; // O(n) linear scan
Real-world example Storing a cache of user sessions keyed by session ID, where fast lookup by ID is essential.

Common follow-ups: What happens if you try to access a Dictionary key that doesn't exist, using the indexer versus TryGetValue?

LINQ

When would you choose a HashSet<T> over a List<T>, and what guarantee does it provide?

Intermediate
HashSet<T> guarantees every element is UNIQUE (adding a duplicate is a silent no-op) and provides O(1) average .Contains() lookups, unlike List<T>'s O(n) linear .Contains() scan and lack of uniqueness enforcement — ideal when you need fast membership testing or automatic deduplication.
HashSet<int> visitedIds = new();
if (visitedIds.Add(userId)) {
  ProcessUser(userId); // only runs the first time this ID is seen
}
Real-world example Tracking which user IDs have already been processed in a batch job, avoiding duplicate work efficiently.

Common follow-ups: Does HashSet<T> preserve insertion order the way a List<T> does?

Generics

How does Queue<T> differ from Stack<T> in terms of the order items are removed?

Intermediate
Queue<T> is First-In-First-Out (FIFO) — items are removed (Dequeue) in the same order they were added (Enqueue); Stack<T> is Last-In-First-Out (LIFO) — the most recently added item (Push) is the first one removed (Pop).
Queue<string> queue = new();
queue.Enqueue("first"); queue.Enqueue("second");
Console.WriteLine(queue.Dequeue()); // 'first'

Stack<string> stack = new();
stack.Push("first"); stack.Push("second");
Console.WriteLine(stack.Pop()); // 'second'
Real-world example Using Queue<T> for a print job or task processing queue; Stack<T> for an undo/redo history or a depth-first traversal.

Common follow-ups: Which of these two collections would you use to implement a breadth-first graph traversal?

Iterators & yield return

Showing 1–10 of 16