What is the difference between an array,
List<T>andArrayList?An array has a fixed length;
List<T>is a generic, resizable list backed by an array;ArrayListis the old non-generic version that boxes every value type.C#using System; using System.Collections.Generic; class Program { static void Main() { int[] arr = { 3, 1, 2 }; Array.Sort(arr); Console.WriteLine(string.Join(",", arr) + " length " + arr.Length); var list = new List<int> { 3, 1, 2 }; list.Add(5); list.Remove(1); Console.WriteLine(string.Join(",", list) + " count " + list.Count); } }List<T>doubles its array when full, soAddis O(1) amortized. See List.What is the difference between
IEnumerable<T>,ICollection<T>andIList<T>?They are layers:
IEnumerable<T>can only be enumerated;ICollection<T>addsCount,Add,RemoveandContains;IList<T>adds access by index. Accept the smallest interface a method needs. Trap: an array implementsIList<T>, butAddon it throwsNotSupportedException.How does
Dictionary<TKey, TValue>work internally?Dictionaryis a hash table:GetHashCode()on the key picks a bucket andEquals()finds the entry, so operations are O(1) on average and O(n) when many keys collide.C#using System; using System.Collections.Generic; class Program { static void Main() { string text = "the cat and the hat and the bat"; var counts = new Dictionary<string, int>(); foreach (var word in text.Split(' ')) { int c; counts.TryGetValue(word, out c); // c is 0 when the key is missing counts[word] = c + 1; } Console.WriteLine(counts["the"] + " " + counts["and"]); Console.WriteLine(counts.ContainsKey("dog")); } }Traps:
dict[key]throwsKeyNotFoundExceptionfor a missing key, and writes are not thread-safe. See the hash table visualization.Practice it: Two Sum, First Unique Character in a String
What is a
HashSet<T>, and when would you use it?HashSet<T>stores unique values with O(1) averageAdd,RemoveandContains, and no order. Use it for "seen before" checks and set operations.C#using System; using System.Collections.Generic; class Program { static void Main() { var seen = new HashSet<int>(); int[] nums = { 4, 2, 7, 2, 9 }; foreach (int n in nums) { if (!seen.Add(n)) // Add returns false when the value is already there Console.WriteLine("duplicate: " + n); } var a = new HashSet<int> { 1, 2, 3 }; a.IntersectWith(new[] { 2, 3, 4 }); Console.WriteLine(string.Join(",", a)); } }Replacing a list's O(n)
Containswith aHashSetinside a loop turns O(n²) into O(n).Practice it: Contains Duplicate, Intersection of Two Arrays
When does a LINQ
Wherequery actually run?C#using System; using System.Collections.Generic; using System.Linq; class Program { static void Main() { var nums = new List<int> { 1, 2, 3 }; var big = nums.Where(n => n > 1); nums.Add(4); Console.WriteLine(big.Count()); } }Wherebuilds a query that runs each time it is enumerated (deferred execution).Count()enumerates it after4was added, sees2, 3, 4and prints3. CallToList()to freeze a result; enumerating an expensive query twice does the work twice.What is the difference between
First,FirstOrDefault,SingleandSingleOrDefault?Firstreturns the first match and throws if there is none;Singlereturns the only match and throws on zero or more than one. TheOrDefaultversions returndefault(T)when nothing matches, butSingleOrDefaultstill throws on two or more.C#using System; using System.Linq; class Program { static void Main() { int[] nums = { 4, 8, 15, 16 }; Console.WriteLine(nums.First(n => n > 5)); Console.WriteLine(nums.FirstOrDefault(n => n > 100)); try { Console.WriteLine(nums.Single(n => n > 5)); } catch (InvalidOperationException) { Console.WriteLine("Single threw: more than one match"); } } }Use
Singlewhen exactly one match is a rule, such as a lookup by primary key.When does the body of a
yield returnmethod start running?C#using System; using System.Collections.Generic; class Program { static IEnumerable<int> Gen() { Console.Write("start "); yield return 1; Console.Write("mid "); yield return 2; } static void Main() { var g = Gen(); Console.Write("before "); foreach (var x in g) Console.Write(x + " "); Console.WriteLine(); } }Calling an iterator such as
Gen()runs none of its body.foreachstarts it on the firstMoveNext; it runs to eachyield returnand pauses, sobeforeprints first, thenstart 1, thenmid 2. See IEnumerable and yield.What happens if you remove items from a
List<T>inside aforeachloop?The enumerator detects the change and throws
InvalidOperationExceptionon the next step. UseRemoveAll, loop backwards withfor, or iterate over a copy.C#using System; using System.Collections.Generic; class Program { static void Main() { var nums = new List<int> { 1, 2, 3, 4, 5, 6 }; try { foreach (var n in nums) if (n % 2 == 0) nums.Remove(n); } catch (InvalidOperationException e) { Console.WriteLine(e.GetType().Name); } nums = new List<int> { 1, 2, 3, 4, 5, 6 }; nums.RemoveAll(n => n % 2 == 0); Console.WriteLine(string.Join(",", nums)); nums = new List<int> { 1, 2, 3, 4, 5, 6 }; for (int i = nums.Count - 1; i >= 0; i--) if (nums[i] % 2 == 0) nums.RemoveAt(i); Console.WriteLine(string.Join(",", nums)); } }Backwards, because removing at
ishifts later items left and a forward loop skips one.Practice it: Move Zeroes
How do you group items with LINQ? Show
GroupBywith an example.GroupBy(keySelector)returns groups, each with aKeyand the items that share it, like SQL'sGROUP BY.C#using System; using System.Linq; class Program { static void Main() { string[] words = { "eat", "tea", "tan", "ate", "nat", "bat" }; var groups = words .GroupBy(w => new string(w.OrderBy(c => c).ToArray())) .OrderByDescending(g => g.Count()); foreach (var g in groups) Console.WriteLine(g.Key + ": " + string.Join(" ", g)); } }Grouping by sorted letters solves group anagrams. See LINQ.
Practice it: Group Anagrams, Valid Anagram
What is the difference between
SelectandSelectManyin LINQ?Selectmaps each item to one result, so a sequence of lists stays a sequence of lists.SelectManymaps each item to a sequence and flattens them all into one.C#using System; using System.Collections.Generic; using System.Linq; class Program { static void Main() { var teams = new Dictionary<string, string[]> { { "backend", new[] { "Ravi", "Meera" } }, { "frontend", new[] { "Arjun" } } }; var counts = teams.Select(t => t.Value.Length); Console.WriteLine(string.Join(",", counts)); var everyone = teams.SelectMany(t => t.Value); Console.WriteLine(string.Join(",", everyone)); } }What is the difference between
IEnumerable<T>andIQueryable<T>?IEnumerable<T>runs LINQ in memory with compiled delegates.IQueryable<T>builds an expression tree that a provider such as Entity Framework Core translates into SQL.// IQueryable: the filter becomes WHERE in SQL, only matching rows come back var active = db.Users.Where(u => u.IsActive).ToList(); // AsEnumerable switches to in-memory LINQ: every row is loaded, then filtered var slow = db.Users.AsEnumerable().Where(u => u.IsActive).ToList();Trap:
AsEnumerable, or passing the query to anIEnumerable<T>parameter, silently moves filtering from the database into your app.Which .NET collection would you choose for each job:
List,Queue,Stack,LinkedList,SortedDictionary,ConcurrentDictionary?Choose by the operation you do most.
Need Collection indexed data List<T>first in, first out Queue<T>last in, first out Stack<T>lookup by key Dictionary<K,V>sorted keys SortedDictionary<K,V>priority order (.NET 6 and later) PriorityQueue<T,P>shared between threads ConcurrentDictionary<K,V>LinkedList<T>is rarely faster thanList<T>, whose contiguous array suits the CPU cache.Practice it: Implement Queue Using Stacks
C# Collections and LINQ Interview Questions
List, Dictionary, HashSet and the LINQ behavior that trips people up: deferred execution, yield, IQueryable.