List<T> is the workhorse collection in C#, a resizable array that adapts to your data instead of forcing you to know its size up front.
This collection of 35 C# List exercises covers everything from basic adding and removing to sorting, searching, filtering, and building small interactive programs powered entirely by lists.
Each exercise includes a Practice Problem, Purpose, Hint, and a full Solution with Explanation, so you build a strong, practical understanding of List<T> in real code.
Also, See: C# Exercises with 22 topic-wise sets and 620+ practice questions.
What You’ll Practice
- Fundamentals: Creating, adding, removing, and counting list items.
- Searching & Sorting:
Contains(),IndexOf(),Sort(), and custom comparisons. - Manipulation: Removing duplicates, reversing, and filtering lists.
- Practical Use: Building small menu-driven, list-backed programs.
+ Table Of Contents (35 Exercises)
Table of contents
- Exercise 1: Initialize and Print
- Exercise 2: Add & Insert
- Exercise 3: Remove Elements
- Exercise 4: Check Existence
- Exercise 5: Count and Clear
- Exercise 6: Find Index
- Exercise 7: Sum and Average
- Exercise 8: Min and Max
- Exercise 9: List to Array
- Exercise 10: Reverse a List
- Exercise 11: Filter Even Numbers
- Exercise 12: Remove Duplicates
- Exercise 13: Sort Lists
- Exercise 14: Merge Two Lists
- Exercise 15: Find All Matches
- Exercise 16: Insert Range
- Exercise 17: Check for Substring
- Exercise 18: Update Elements
- Exercise 19: Split a List
- Exercise 20: List of Custom Objects
- Exercise 21: Forward and Backward Traversal
- Exercise 22: First and Last Manipulation
- Exercise 23: Mid-List Insertion
- Exercise 24: Targeted Node Removal
- Exercise 25: Convert to Standard List
- Exercise 26: LINQ Filtering & Sorting
- Exercise 27: Group By
- Exercise 28: Custom Object Sorting
- Exercise 29: Chunking a List
- Exercise 30: Flattening Lists
- Exercise 31: Binary Search
- Exercise 32: Dictionary Conversion
- Exercise 33: Check Conditions (All/Any)
- Exercise 34: Rotate Elements
- Exercise 35: Frequency Count
Exercise 1: Initialize and Print
Practice Problem: Create a list of strings containing 5 fruit names. Print each fruit on a new line using a foreach loop.
Purpose: This exercise helps you practice the most basic list workflow: initializing a List<T> with values right away, and iterating over it with foreach.
Given Input: List<string> fruits = new List<string> { "Apple", "Banana", "Cherry", "Date", "Elderberry" };
Expected Output:
Apple Banana Cherry Date Elderberry
▼ Hint
- Use a collection initializer to fill the list with all 5 names at once.
- Use a
foreach (string fruit in fruits)loop to visit each element. - Print each fruit with its own
Console.WriteLinecall.
▼ Solution & Explanation
Explanation:
List<string> fruits = new List<string> { ... }: Creates and populates the list in a single statement using a collection initializer.foreach (string fruit in fruits): Visits every element in the list, one at a time, in the order they were added.Console.WriteLine(fruit): Prints the current fruit before moving on to the next iteration.
Exercise 2: Add & Insert
Practice Problem: Create an empty list of integers. Add the numbers 10, 20, and 30 using .Add(). Then, insert the number 15 at index 1.
Purpose: This exercise helps you practice building up a list one element at a time with Add(), and shows how Insert() places a value at a specific position, shifting everything after it one slot to the right.
Given Input: numbers.Add(10); numbers.Add(20); numbers.Add(30); numbers.Insert(1, 15);
Expected Output: {10, 15, 20, 30}
▼ Hint
- Start with
new List<int>(), an empty list. - Call
.Add()three times to append 10, 20, and 30 in order. - Call
.Insert(1, 15)to place 15 at index 1, pushing 20 and 30 one position later.
▼ Solution & Explanation
Explanation:
new List<int>(): Creates a list with no elements, ready to be built up withAdd()calls.numbers.Add(10): Appends a value to the end of the list, growing it by one element each time.numbers.Insert(1, 15): Places 15 at index 1, shifting the existing elements at that position and after it one slot later.
Exercise 3: Remove Elements
Practice Problem: Create a list of integers from 1 to 10. Remove the number 5 by value, and remove the element at index 0.
Purpose: This exercise helps you practice the difference between Remove(), which deletes the first matching value, and RemoveAt(), which deletes whatever happens to be at a given position.
Given Input: List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
Expected Output: {2, 3, 4, 6, 7, 8, 9, 10}
▼ Hint
- Call
numbers.Remove(5)to delete the value 5 wherever it appears in the list. - Call
numbers.RemoveAt(0)to delete whatever element is currently first in the list. - Do the value removal first, then the index removal, so the index refers to the list’s state after the first removal.
▼ Solution & Explanation
Explanation:
numbers.Remove(5): Searches for the value 5 and removes the first occurrence of it, regardless of where it sits in the list.numbers.RemoveAt(0): Removes whatever element is currently at index 0, which by this point is the value 1.- Remaining list: Every element automatically shifts down to fill the gap left by each removal, so no manual re-indexing is needed.
Exercise 4: Check Existence
Practice Problem: Create a list of colors. Ask the user for a color, and use .Contains() to check if it exists in the list.
Purpose: This exercise helps you practice .Contains() for a simple existence check, without needing to loop through the list or track an index yourself.
Given Input: List<string> colors = new List<string> { "Red", "Green", "Blue", "Yellow" };, checking for "Blue" and "Purple" in place of real console input.
Expected Output:
Blue is in the list. Purple is not in the list.
▼ Hint
- In a real console app, you would capture the color name with
Console.ReadLine(); here a fixed value stands in for that input so the output stays predictable. - Call
colors.Contains(input), which returnstrueorfalse. - Use a ternary expression or an if/else to print a different message depending on the result.
▼ Solution & Explanation
Explanation:
colors.Contains(firstCheck): Scans the list and returnstrueas soon as a matching value is found.- Ternary expression: Picks between two different message strings based on the boolean result of
Contains(). secondCheck: Demonstrates the “not found” branch, since"Purple"was never added to the list.
Exercise 5: Count and Clear
Practice Problem: Create a list of double values. Print the total count of elements using .Count, clear the list using .Clear(), and verify its count is now 0.
Purpose: This exercise helps you practice the Count property and the Clear() method, useful whenever you need to empty a list without replacing it with a brand new instance.
Given Input: List<double> values = new List<double> { 1.1, 2.2, 3.3, 4.4 };
Expected Output:
Count before clear: 4 Count after clear: 0
▼ Hint
Read values.Count once before calling Clear(), and once again afterward, to see the difference.
▼ Solution & Explanation
Explanation:
values.Count: Reports how many elements are currently stored in the list.values.Clear(): Removes every element from the list in one call, leaving the same list instance empty rather than replacing it.- Second
Console.WriteLine: Confirms the list is now empty by readingCountagain after clearing.
Exercise 6: Find Index
Practice Problem: Create a list of names. Find and print the index of a specific name using .IndexOf(). Return -1 if it doesn’t exist.
Purpose: This exercise helps you practice .IndexOf(), which already returns -1 by convention when the value isn’t found, so there’s no need to write your own separate check for a missing element.
Given Input: List<string> names = new List<string> { "Alice", "Bob", "Charlie", "Diana" };, looking up "Charlie" and "Zoe".
Expected Output:
Index of Charlie: 2 Index of Zoe: -1
▼ Hint
- Call
names.IndexOf("Charlie")to get the zero-based position of that name. - Call
names.IndexOf("Zoe")for a name that was never added. - No extra logic is required for the missing case,
IndexOf()already returns -1 on its own.
▼ Solution & Explanation
Explanation:
names.IndexOf("Charlie"): Returns 2, since"Charlie"is the third element at zero-based index 2.names.IndexOf("Zoe"): Returns -1 automatically, since"Zoe"was never added to the list.
Exercise 7: Sum and Average
Practice Problem: Create a list of integers. Calculate and print their sum and average without using LINQ, using a loop instead.
Purpose: This exercise helps you practice manually accumulating a total with a loop, and reinforces why one of the two numbers involved in a division needs to be cast to a floating-point type to get a decimal result.
Given Input: List<int> numbers = new List<int> { 4, 8, 15, 16, 23, 42 };
Expected Output:
Sum = 108 Average = 18
▼ Hint
- Initialize a running total to 0 before the loop.
- Use a
foreachloop to add each number to the running total. - Cast the sum to
doublebefore dividing bynumbers.Count, so the average isn’t accidentally truncated by integer division.
▼ Solution & Explanation
Explanation:
int sum = 0: Starts the running total at zero before any numbers have been added.sum += number: Adds each element to the total as the loop visits it.(double)sum / numbers.Count: Casts the sum todoublefirst, so the division produces a decimal result instead of being rounded down as integer division would.
Exercise 8: Min and Max
Practice Problem: Write a program to find the maximum and minimum values in a list of integers using a for loop.
Purpose: This exercise helps you practice the classic running-maximum and running-minimum pattern, tracking the best value seen so far while scanning through a list by index.
Given Input: List<int> numbers = new List<int> { 34, 12, 89, 5, 67, 23 };
Expected Output:
Max = 89 Min = 5
▼ Hint
- Start both
maxandminatnumbers[0]before the loop begins. - Loop from index 1 to the end of the list with a
forloop. - Update
maxwhenever you find a larger value, and updateminwhenever you find a smaller one.
▼ Solution & Explanation
Explanation:
int max = numbers[0]; int min = numbers[0];: Seeds both trackers with the first element, giving them a valid starting point to compare against.for (int i = 1; i < numbers.Count; i++): Starts at index 1 since index 0 was already used to seedmaxandmin.if (numbers[i] > max) max = numbers[i];: Updates the running maximum whenever a larger value is found.if (numbers[i] < min) min = numbers[i];: Updates the running minimum whenever a smaller value is found.
Exercise 9: List to Array
Practice Problem: Create a list of strings, convert it into a standard array using .ToArray(), and print the array elements.
Purpose: This exercise helps you practice converting between a resizable List<T> and a fixed-size array, which is sometimes required when calling an older API that expects an array parameter.
Given Input: List<string> fruits = new List<string> { "Apple", "Banana", "Cherry" };
Expected Output:
Apple Banana Cherry
▼ Hint
- Call
.ToArray()on the list to produce a newstring[]. - The resulting array is a completely separate copy, not a view into the original list.
- Loop through the array the same way you would loop through a list, with
foreach.
▼ Solution & Explanation
Explanation:
fruits.ToArray(): Copies every element from the list into a brand new, fixed-size array.string[] fruitArray: Declares the result as a standard array type, distinct from the originalList<string>.foreach (string fruit in fruitArray): Iterates over the array exactly the same way as it would over the original list.
Exercise 10: Reverse a List
Practice Problem: Create a list of characters (A to E) and reverse the order of elements using the .Reverse() method.
Purpose: This exercise helps you practice .Reverse(), which flips the order of a list’s elements in place, without needing to build a second list or loop backward manually.
Given Input: List<char> letters = new List<char> { 'A', 'B', 'C', 'D', 'E' };
Expected Output: {E, D, C, B, A}
▼ Hint
- Call
letters.Reverse()directly on the list, with no arguments. - This method reverses the list in place, it does not return a new list.
- Print the list afterward to see the new order.
▼ Solution & Explanation
Explanation:
letters.Reverse(): Flips the order of every element in the list directly, without allocating a second list.- In-place modification: The original
letterslist itself is changed, so no reassignment likeletters = letters.Reverse()is needed or even valid here. string.Join(", ", letters): Combines the now-reversed elements into a single readable line for display.
Exercise 11: Filter Even Numbers
Practice Problem: Given a list of integers, create a new list that contains only the even numbers from the original list.
Purpose: This exercise helps you practice building a filtered list by hand with a loop and the modulo operator, the same underlying idea LINQ’s Where() uses internally.
Given Input: List<int> numbers = new List<int> { 12, 7, 8, 3, 4, 15, 22, 9 };
Expected Output: {12, 8, 4, 22}
▼ Hint
- Create an empty result list before the loop starts.
- Loop through the original list with
foreach. - Use
number % 2 == 0to test whether the current number is even. - Add matching numbers to the result list as you go.
▼ Solution & Explanation
Explanation:
List<int> evens = new List<int>(): Starts a fresh, empty list to collect only the numbers that pass the even check.number % 2 == 0: Tests whether dividing by 2 leaves no remainder, which is the standard way to check for an even number.evens.Add(number): Appends the current number to the result list only when it passes the even check.
Exercise 12: Remove Duplicates
Practice Problem: Write a program that takes a list with duplicate integers and removes them, keeping only unique values, without using HashSet.
Purpose: This exercise helps you practice building a unique list manually with .Contains(), and shows the trade-off of this approach: it is simple to write but slower on large lists than a HashSet-based solution would be.
Given Input: List<int> numbers = new List<int> { 1, 2, 2, 3, 4, 4, 4, 5, 1 };
Expected Output: {1, 2, 3, 4, 5}
▼ Hint
- Create an empty result list to hold only unique values.
- Loop through the original list with
foreach. - Before adding a number, check
!unique.Contains(number)to make sure it hasn’t already been added. - Only add the number to the result list if that check passes.
▼ Solution & Explanation
Explanation:
!unique.Contains(number): Checks whether this exact value has already been placed into the result list before adding it again.- Order preserved: Since values are added in the order they are first seen, the result keeps the original list’s ordering rather than sorting or scrambling it.
- Without
HashSet: EachContains()call scans the growing result list directly, which is simple to reason about but does more work than a hash-based lookup would.
Exercise 13: Sort Lists
Practice Problem: Create a list of random integers. Sort it in ascending order, print it, and then sort it in descending order.
Purpose: This exercise helps you practice the default .Sort() method for ascending order, and shows how passing a custom comparison delegate flips the sort order to descending without writing a separate sorting algorithm.
Given Input: List<int> numbers = new List<int> { 42, 17, 8, 99, 23, 4 };
Expected Output:
Ascending: {4, 8, 17, 23, 42, 99}
Descending: {99, 42, 23, 17, 8, 4}
▼ Hint
- Call
numbers.Sort()with no arguments to sort in ascending order. - Call
numbers.Sort((a, b) => b.CompareTo(a))to sort the same list in descending order. - Both calls sort the list in place, so print it again after each call to see the new order.
▼ Solution & Explanation
Explanation:
numbers.Sort(): Sorts the list in place using the default ascending comparison for integers.numbers.Sort((a, b) => b.CompareTo(a)): Supplies a custom comparison that reverses the usual result, producing a descending order instead.- In-place sorting: Both calls modify the same
numberslist directly, so the second sort completely overwrites the ordering left by the first.
Exercise 14: Merge Two Lists
Practice Problem: Create two separate lists of strings. Combine them into a third list, ensuring no duplicate strings are added.
Purpose: This exercise helps you practice combining two lists while guarding against duplicates, similar to the duplicate-removal pattern but applied across two separate sources instead of one.
Given Input: listA = { "Apple", "Banana", "Cherry" } and listB = { "Banana", "Date", "Cherry", "Fig" }
Expected Output: Apple, Banana, Cherry, Date, Fig
▼ Hint
- Start the merged list as a copy of the first list, using the
List<string>constructor. - Loop through the second list, checking
!merged.Contains(item)before adding each one. - This way, entries that appear in both lists only end up in the merged result once.
▼ Solution & Explanation
Explanation:
new List<string>(listA): Creates an independent copy of the first list, so the originallistAis never modified by the merge.!merged.Contains(item): Skips any string from the second list that already exists in the merged result, whether it came from the first list or an earlier item in the second.- Result order: Keeps every item from
listAfirst, followed by only the new, non-duplicate items fromlistB.
Exercise 15: Find All Matches
Practice Problem: Use .FindAll() to extract all words longer than 5 characters from a list of strings.
Purpose: This exercise helps you practice .FindAll(), a built-in List<T> method that takes a predicate delegate and returns every matching element as a new list, without writing a manual loop.
Given Input: List<string> words = new List<string> { "cat", "elephant", "dog", "giraffe", "ant", "butterfly" };
Expected Output: elephant, giraffe, butterfly
▼ Hint
- Call
words.FindAll(word => word.Length > 5)directly on the list. - The predicate lambda should return
truefor exactly the words you want to keep. - The result is already a
List<string>, ready to print or use directly.
▼ Solution & Explanation
Explanation:
words.FindAll(word => word.Length > 5): Runs the predicate against every word and collects only the ones where it returnstrue.word.Length > 5: The actual condition being tested, keeping only words with more than 5 characters.longWords: A brand new list containing just the matches, leaving the originalwordslist untouched.
Exercise 16: Insert Range
Practice Problem: Create a list of numbers (1, 2, 6, 7). Create a second list (3, 4, 5). Use .InsertRange() to insert the second list into the middle of the first list so it becomes sequential.
Purpose: This exercise helps you practice .InsertRange(), which inserts an entire collection at a specific position in one call, instead of looping and calling .Insert() once per element.
Given Input: primary = { 1, 2, 6, 7 } and toInsert = { 3, 4, 5 }
Expected Output: {1, 2, 3, 4, 5, 6, 7}
▼ Hint
- Figure out which index in
primarythe gap sits at, right between 2 and 6. - Call
primary.InsertRange(index, toInsert)at that position. - Every element in
toInsertgets inserted in order, and everything after the insertion point shifts to make room.
▼ Solution & Explanation
Explanation:
primary.InsertRange(2, toInsert): Inserts every element oftoInsertstarting at index 2, which is exactly where the value 6 currently sits.- Shifted elements: The values 6 and 7 automatically move later in the list to make room for the three newly inserted numbers.
- Order preserved: The inserted numbers 3, 4, and 5 keep their original relative order from
toInsert.
Exercise 17: Check for Substring
Practice Problem: Given a list of book titles, filter and print only the titles that contain the word “The”.
Purpose: This exercise helps you practice combining .FindAll() with a string method like .Contains(), applying the same filtering pattern from Exercise 15 to a text-matching condition instead of a length check.
Given Input: { "The Great Gatsby", "Moby Dick", "The Catcher in the Rye", "1984", "The Hobbit" }
Expected Output:
The Great Gatsby The Catcher in the Rye The Hobbit
▼ Hint
- Call
titles.FindAll(title => title.Contains("The")). - Remember that
.Contains()on a string is case-sensitive by default, so lowercase “the” inside a title won’t count as a match on its own. - Print each matching title on its own line with a
foreachloop.
▼ Solution & Explanation
Explanation:
title.Contains("The"): Checks whether the exact substring “The” appears anywhere in the title, including at the very start."Moby Dick"and"1984": Correctly excluded, since neither title contains the substring “The” at all."The Catcher in the Rye": Still matches, because it contains “The” with a capital T at the start, even though it also contains a lowercase “the” later on.
Exercise 18: Update Elements
Practice Problem: Write a program that iterates through a list of integers and multiplies every odd number by 2.
Purpose: This exercise helps you practice modifying a list’s elements in place, and shows why a for loop with an index is needed here instead of foreach, since the iteration variable in a foreach loop cannot be assigned back into the list.
Given Input: List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6 };
Expected Output: {2, 2, 6, 4, 10, 6}
▼ Hint
- Use a
forloop with an index variable, rather thanforeach, since you need to write a new value back into the list. - Check
numbers[i] % 2 != 0to test whether the current element is odd. - If it is, multiply it by 2 and assign the result back with
numbers[i] *= 2.
▼ Solution & Explanation
Explanation:
for (int i = 0; i < numbers.Count; i++): Walks through every position in the list by index, which is required since the elements themselves need to be replaced.numbers[i] % 2 != 0: Tests whether the value at the current position is odd.numbers[i] *= 2: Doubles the value in place at that index, directly modifying the original list rather than building a new one.
Exercise 19: Split a List
Practice Problem: Take a list of 10 numbers and split it into two separate lists: one for the first 5 elements and one for the last 5 elements.
Purpose: This exercise helps you practice .GetRange(), which extracts a contiguous slice of a list into a brand new list, without needing to loop and copy elements manually.
Given Input: List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
Expected Output:
First half: {1, 2, 3, 4, 5}
Second half: {6, 7, 8, 9, 10}
▼ Hint
- Call
numbers.GetRange(0, 5)to grab the first 5 elements, starting at index 0. - Call
numbers.GetRange(5, 5)to grab the next 5 elements, starting at index 5. - The second argument to
GetRange()is always a count, not an ending index.
▼ Solution & Explanation
Explanation:
numbers.GetRange(0, 5): Copies 5 elements starting at index 0 into a brand new list.numbers.GetRange(5, 5): Copies the next 5 elements, starting at index 5, into a second new list.- Original
numberslist: Remains completely unchanged, sinceGetRange()always returns a separate copy.
Exercise 20: List of Custom Objects
Practice Problem: Create a Student class with properties Id and Name. Create a List<Student>, add 3 students, and print their details by iterating through the list.
Purpose: This exercise helps you practice storing your own custom class inside a List<T>, rather than a built-in type like int or string, and accessing each object’s properties while iterating.
Given Input: Three students with Ids 1, 2, and 3, named Alice, Bob, and Charlie.
Expected Output:
Id: 1, Name: Alice Id: 2, Name: Bob Id: 3, Name: Charlie
▼ Hint
- Give the
Studentclass two auto-implemented properties,IdandName. - Use object initializer syntax,
new Student { Id = 1, Name = "Alice" }, to create each student. - Loop through the
List<Student>withforeach, reading.Idand.Nameoff each element.
▼ Solution & Explanation
Explanation:
public int Id { get; set; }: An auto-implemented property, givingStudenta simple readable and writable field without a manually written backing field.new Student { Id = 1, Name = "Alice" }: Creates a fully populatedStudentobject in a single expression using object initializer syntax.foreach (Student student in students): Iterates over the list of custom objects exactly like it would over a list of any built-in type.student.Idandstudent.Name: Reads each property directly off the currentStudentobject for display.
Exercise 21: Forward and Backward Traversal
Practice Problem: Create a LinkedList<string> of steps in a workflow. Print the list from first to last using .Next, and then from last to first using .Previous.
Purpose: This exercise helps you practice manually walking a LinkedList<T> node by node, using its First and Last properties as starting points and .Next or .Previous to move along the chain.
Given Input: A workflow with the steps Design, Develop, Test, and Deploy added in that order.
Expected Output:
Forward: Design -> Develop -> Test -> Deploy Backward: Deploy -> Test -> Develop -> Design
▼ Hint
- Start a node reference at
workflow.Firstfor the forward pass. - Loop with a
while (current != null)condition, moving tocurrent.Nexteach time. - Repeat the same idea for the backward pass, starting at
workflow.Lastand moving throughcurrent.Previousinstead.
▼ Solution & Explanation
Explanation:
workflow.Firstandworkflow.Last: Give direct access to the first and last nodes of the linked list without needing to traverse to find them.current.Next: Moves the reference to the following node, or tonullonce the end of the list is reached.currentBack.Previous: Moves the reference backward toward the beginning of the list, the mirror image of.Next.
Exercise 22: First and Last Manipulation
Practice Problem: Create a list of tasks. Use .AddFirst() to insert high-priority tasks and .AddLast() for low-priority tasks. Remove them using .RemoveFirst() and .RemoveLast().
Purpose: This exercise helps you practice LinkedList<T>‘s constant-time operations at both ends, useful whenever new items need to jump to the front of a queue-like structure instead of always going to the back.
Given Input: tasks.AddLast("Write report"); tasks.AddFirst("Fix critical bug"); tasks.AddLast("Update docs");
Expected Output:
Tasks: Fix critical bug, Write report, Update docs After removing first and last: Write report
▼ Hint
- Use
LinkedList<string>, since it is the collection that actually offersAddFirst(),AddLast(),RemoveFirst(), andRemoveLast(). - Call
.AddFirst()for anything urgent, pushing it ahead of everything already queued. - Call
.RemoveFirst()and.RemoveLast()afterward to drop whichever tasks currently sit at each end.
▼ Solution & Explanation
Explanation:
tasks.AddFirst("Fix critical bug"): Places the urgent task at the very front, ahead of the task already added withAddLast().tasks.RemoveFirst(): Removes whatever is currently at the front of the list, here the high-priority bug fix.tasks.RemoveLast(): Removes whatever is currently at the back of the list, here the low-priority documentation update.
Exercise 23: Mid-List Insertion
Practice Problem: Create a linked list of numbers (1 -> 2 -> 4). Find the node containing 2 using .Find(), and use .AddAfter() to insert the missing 3.
Purpose: This exercise helps you practice locating a specific node with .Find(), then using that exact node reference with .AddAfter() to insert a new value at a precise position.
Given Input: numbers.AddLast(1); numbers.AddLast(2); numbers.AddLast(4);
Expected Output: {1, 2, 3, 4}
▼ Hint
- Call
numbers.Find(2)to get theLinkedListNode<int>that holds the value 2. - Pass that node into
numbers.AddAfter(node, 3). - The new value 3 is inserted directly after the found node, without disturbing anything before it.
▼ Solution & Explanation
Explanation:
numbers.Find(2): Scans the list looking for the first node whose value equals 2, returning a direct reference to that node.numbers.AddAfter(node, 3): Inserts a brand new node holding 3 immediately following the found node.- Resulting order: The list becomes 1, 2, 3, 4, exactly filling the gap that was originally missing.
Exercise 24: Targeted Node Removal
Practice Problem: Given a linked list of songs, find a specific song node using .Find() and remove it directly by passing the node object into .Remove().
Purpose: This exercise helps you practice the node-based overload of .Remove(), which deletes an exact, already-located node directly rather than searching the list again by value.
Given Input: A playlist containing “Bohemian Rhapsody”, “Stairway to Heaven”, “Hotel California”, and “Imagine”.
Expected Output: Bohemian Rhapsody, Stairway to Heaven, Imagine
▼ Hint
- Call
songs.Find("Hotel California")to get a reference to that specific node. - Check that the result isn’t
nullbefore removing, in case the song wasn’t in the list at all. - Pass the node itself into
songs.Remove(songNode), rather than passing the string value again.
▼ Solution & Explanation
Explanation:
songs.Find("Hotel California"): Locates the node holding that exact string, or returnsnullif no such song exists in the list.if (songNode != null): Guards against callingRemove()on a node that was never found.songs.Remove(songNode): Unlinks that exact node from the list directly, relying on the node reference rather than searching by value a second time.
Exercise 25: Convert to Standard List
Practice Problem: Create a LinkedList<int>. Write a method to copy all its elements into a standard List<int> without using built-in LINQ methods.
Purpose: This exercise helps you practice manually walking a linked list node by node to build an equivalent List<T>, reinforcing how a linked list’s node-based structure differs from a list’s index-based one.
Given Input: source.AddLast(10); source.AddLast(20); source.AddLast(30); source.AddLast(40);
Expected Output: {10, 20, 30, 40}
▼ Hint
- Create an empty
List<int>to hold the converted result. - Start a node reference at
source.First. - Loop with
while (current != null), addingcurrent.Valueto the list and moving tocurrent.Nexteach time.
▼ Solution & Explanation
Explanation:
LinkedListNode<int> current = source.First: Starts the traversal at the first node in the linked list.result.Add(current.Value): Copies the value out of the current node into the destination list.current = current.Next: Advances to the following node, continuing untilcurrentbecomesnullat the end of the list.
Exercise 26: LINQ Filtering & Sorting
Practice Problem: Given a List<Product> with properties Name, Price, and Category, use LINQ to find all products in the “Electronics” category with a price greater than $500, sorted by price descending.
Purpose: This exercise helps you practice chaining Where() with multiple conditions and OrderByDescending() in a single LINQ pipeline, a very common combination when querying a list of custom objects.
Given Input: Five products across the Electronics and Furniture categories, with prices ranging from 150 to 1200.
Expected Output:
Laptop: 1200 Smartphone: 800 Monitor: 600
▼ Hint
- Call
Where(p => p.Category == "Electronics" && p.Price > 500)to apply both conditions at once. - Chain
OrderByDescending(p => p.Price)onto the filtered result. - Loop through the final sequence with
foreachto print each matching product.
▼ Solution & Explanation
Explanation:
p.Category == "Electronics" && p.Price > 500: Combines both filtering rules into a single condition, so a product must satisfy both to pass through.OrderByDescending(p => p.Price): Arranges the filtered products from most expensive to least expensive.- Method chaining:
Where()andOrderByDescending()are linked directly, so filtering happens before sorting in a single readable pipeline.
Exercise 27: Group By
Practice Problem: Given a List<Employee> with properties Name, Department, and Salary, use LINQ to group employees by their Department and print the department names along with their average salary.
Purpose: This exercise helps you practice GroupBy() combined with an aggregate like Average() computed per group, rather than across the whole list at once.
Given Input: Five employees split across the Engineering, Sales, and Marketing departments.
Expected Output:
Engineering: 100000 Sales: 67500 Marketing: 60000
▼ Hint
- Call
employees.GroupBy(emp => emp.Department)to cluster employees by department. - Loop through the resulting groups, each of which exposes a
Key(the department name). - Inside the loop, call
group.Average(emp => emp.Salary)to compute that specific department’s average.
▼ Solution & Explanation
Explanation:
GroupBy(emp => emp.Department): Clusters every employee into a group keyed by their department name.IGrouping<string, Employee>: Represents one department’s group, exposing both itsKeyand the employees inside it.group.Average(emp => emp.Salary): Computes the mean salary using only the employees within that specific group, not the entire company.
Exercise 28: Custom Object Sorting
Practice Problem: Create a List<Person> with Name and Age. Sort the list by Age using a custom IComparer<Person>.
Purpose: This exercise helps you practice implementing IComparer<T> as a standalone, reusable class, an alternative to passing a lambda directly into .Sort() when the comparison logic is worth naming and reusing elsewhere.
Given Input: Four people aged 30, 22, 45, and 28.
Expected Output:
Bob: 22 Diana: 28 Alice: 30 Charlie: 45
▼ Hint
- Implement
IComparer<Person>with aCompare(Person a, Person b)method. - Inside
Compare(), delegate toa.Age.CompareTo(b.Age)rather than writing custom comparison logic by hand. - Pass a new instance of your comparer class into
people.Sort(new AgeComparer()).
▼ Solution & Explanation
Explanation:
IComparer<Person>: Defines a reusable comparison rule as its own class, rather than a one-off inline lambda.a.Age.CompareTo(b.Age): Returns a negative, zero, or positive number depending on how the two ages compare, exactly whatSort()needs to order the list.people.Sort(new AgeComparer()): Hands the sorting logic off to the comparer instance, sorting the list in place by ascending age.
Exercise 29: Chunking a List
Practice Problem: Write a method that breaks a large List<int> into a list of smaller lists (chunks) of a specified size.
Purpose: This exercise helps you practice building a List<List<int>> from a flat list, stepping through the source in fixed-size strides with .GetRange() while carefully handling a final chunk that may be smaller than the rest.
Given Input: List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };, with a chunk size of 3.
Expected Output:
{1, 2, 3}
{4, 5, 6}
{7, 8, 9}
{10}
▼ Hint
- Loop over the source list with a
forloop, stepping forward bychunkSizeeach iteration instead of by 1. - At each step, use
Math.Min(chunkSize, source.Count - i)to figure out how many elements are actually left to take. - Call
source.GetRange(i, remaining)to grab that chunk, and add it to the result list of chunks. - This naturally handles a final chunk that has fewer elements than
chunkSize.
▼ Solution & Explanation
Explanation:
for (int i = 0; i < source.Count; i += chunkSize): Jumps forward by a full chunk’s worth of elements on every iteration, instead of one at a time.Math.Min(chunkSize, source.Count - i): Prevents the final chunk from trying to read past the end of the source list when it has fewer thanchunkSizeelements left.source.GetRange(i, remaining): Extracts exactly that chunk’s worth of elements as its own independent list.
Exercise 30: Flattening Lists
Practice Problem: Create a List<List<int>>, a list of integer lists. Use LINQ’s .SelectMany() to flatten it into a single List<int>.
Purpose: This exercise helps you practice .SelectMany(), which is specifically designed to collapse a sequence of sequences into one flat sequence, unlike Select() which would leave the nested lists intact.
Given Input: Three inner lists, { 1, 2, 3 }, { 4, 5 }, and { 6, 7, 8, 9 }.
Expected Output: {1, 2, 3, 4, 5, 6, 7, 8, 9}
▼ Hint
- Call
nested.SelectMany(list => list)directly on the outer list. - Each inner list gets expanded and merged into one continuous sequence, in the order the inner lists themselves appear.
- Chain
.ToList()at the end to materialize the flattened sequence into an actualList<int>.
▼ Solution & Explanation
Explanation:
List<List<int>> nested: Represents a list where each element is itself a full list of integers, rather than a single integer.nested.SelectMany(list => list): Projects each inner list to itself and merges all of them into one single, flat sequence..ToList(): Converts the flattened sequence into a concreteList<int>that can be stored, indexed, or printed like any other list.
Exercise 31: Binary Search
Practice Problem: Create a list of 1,000 sorted integers. Use the .BinarySearch() method to efficiently find the index of a specific number.
Purpose: This exercise helps you practice .BinarySearch(), which locates a value in a sorted list far faster than scanning from the start, but only works correctly if the list is actually sorted beforehand.
Given Input: A list of 1,000 even numbers, 0, 2, 4, and so on up to 1998, searching for the value 742.
Expected Output: Index of 742 = 371
▼ Hint
- Build the list so its values are already in ascending order, since
.BinarySearch()assumes this and gives unreliable results otherwise. - Call
numbers.BinarySearch(742)directly on the sorted list. - The returned index tells you exactly where that value sits, found in far fewer comparisons than a simple linear scan would need.
▼ Solution & Explanation
Explanation:
numbers.Add(i * 2): Builds a list of even numbers, 0, 2, 4, all the way up to 1998, already in sorted order.numbers.BinarySearch(742): Repeatedly checks the middle of the remaining range and narrows the search by half each time, instead of checking every element in order.- Result, 371: Since every value in the list is exactly double its index, searching for 742 correctly lands on index 371.
Exercise 32: Dictionary Conversion
Practice Problem: Given a List<Student>, convert it into a Dictionary<int, Student> where the key is the Student.Id, using LINQ’s .ToDictionary().
Purpose: This exercise helps you practice turning a flat list of objects into a dictionary keyed by one of that object’s own properties, making later lookups by Id instant instead of requiring a scan through the whole list.
Given Input: Three students with Ids 1, 2, and 3, named Alice, Bob, and Charlie.
Expected Output: Student with Id 2: Bob
▼ Hint
- Call
students.ToDictionary(s => s.Id), using just one lambda for the key selector. - When only a key selector is given,
ToDictionary()uses the whole original object as the value automatically. - Look up a specific student directly with the dictionary’s indexer, like
studentById[2].
▼ Solution & Explanation
Explanation:
students.ToDictionary(s => s.Id): Builds a dictionary where each student’sIdbecomes the key and the fullStudentobject becomes the value.studentById[2]: Retrieves the exact student whose Id is 2 in a single, constant-time lookup..Name: Reads a property directly off the retrievedStudentobject, since the dictionary’s value is the whole object, not just a name string.
Exercise 33: Check Conditions (All/Any)
Practice Problem: Given a list of exam scores, use LINQ to check if any student scored 100, and if all students passed, scored above 50.
Purpose: This exercise helps you practice the difference between .Any(), which asks whether at least one element satisfies a condition, and .All(), which asks whether every element satisfies it.
Given Input: List<int> scores = new List<int> { 85, 100, 62, 78, 45, 90 };
Expected Output:
Any student scored 100? True Did all students pass? False
▼ Hint
- Call
scores.Any(score => score == 100), which stops and returnstrueas soon as one match is found. - Call
scores.All(score => score > 50), which stops and returnsfalseas soon as one non-matching score is found. - A single low score is enough to make
All()returnfalse, even if every other score easily passes.
▼ Solution & Explanation
Explanation:
scores.Any(score => score == 100): Returnstruebecause at least one score in the list is exactly 100.scores.All(score => score > 50): Returnsfalsebecause the score of 45 fails the condition, even though every other score passes.- Short-circuiting: Both methods stop scanning as soon as the overall answer is already decided, rather than always checking every element.
Exercise 34: Rotate Elements
Practice Problem: Write a function to rotate a List<T> to the left by k positions, for example, rotating {1, 2, 3, 4} by 1 position results in {2, 3, 4, 1}.
Purpose: This exercise helps you practice building a generic method that works for a list of any element type, and shows how .GetRange() can split a list into two pieces that are then reassembled in swapped order.
Given Input: List<int> numbers = new List<int> { 1, 2, 3, 4 };, rotating left by 1.
Expected Output: {2, 3, 4, 1}
▼ Hint
- Take the modulo of
kby the list’s length first, so aklarger than the list still works correctly. - Grab the elements from index
kto the end with.GetRange(k, count - k). - Grab the first
kelements with.GetRange(0, k). - Append the second piece onto the end of the first piece to get the rotated result.
▼ Solution & Explanation
Explanation:
k = k % count: Wrapskaround the list’s actual length, so rotating by an amount larger than the list still produces a correct result.source.GetRange(k, count - k): Takes everything from indexkonward, which becomes the front of the rotated list.source.GetRange(0, k): Takes the firstkelements, which get moved to the back of the rotated list.RotateLeft<T>: Works for a list of any element type, not just integers, since the method itself is generic.
Exercise 35: Frequency Count
Practice Problem: Given a list of words, use LINQ to count the frequency of each word and output the results as a list of anonymous objects showing the word and its count.
Purpose: This exercise helps you practice combining GroupBy() with an anonymous type projection, a handy way to shape query results into a lightweight, one-off structure without declaring a dedicated class first.
Given Input: { "apple", "banana", "apple", "cherry", "apple", "banana" }
Expected Output:
apple: 3 banana: 2 cherry: 1
▼ Hint
- Call
GroupBy(word => word)to cluster identical words together. - Chain
Select(group => new { Word = group.Key, Count = group.Count() })to shape each group into a small anonymous object. - Since an anonymous type has no name you can write out, the variable holding the results must be declared with
varinstead of an explicit type.
▼ Solution & Explanation
Explanation:
GroupBy(word => word): Clusters every occurrence of the same word into its own group.new { Word = group.Key, Count = group.Count() }: Builds a small anonymous object per group, carrying just the word itself and how many times it appeared.var frequenciesandvar entry: Required here since anonymous types don’t have a name that can be written out explicitly, this is one of the few placesvaris necessary rather than optional.

Leave a Reply