Lambda expressions let you write short, inline functions without the overhead of defining a named method, and they’re the foundation behind LINQ and much of modern C#’s functional-style code.
This collection of 20 C# lambda expression exercises covers writing lambdas with Func<T>, Action<T>, and Predicate<T>, and using them to filter, transform, and process data concisely.
Each exercise includes a Practice Problem, Purpose, Hint, and a full Solution with Explanation, so you get comfortable reading and writing lambda syntax with confidence.
Also, See: C# Exercises with 22 topic-wise sets and 620+ practice questions.
What You’ll Practice
- Syntax: Single-expression and multi-line lambda bodies.
- Delegate Types:
Func<T, TResult>,Action<T>, andPredicate<T>. - Practical Use: Passing lambdas to LINQ methods and collection operations.
- Closures: Capturing outer variables inside a lambda expression.
+ Table Of Contents (20 Exercises)
Table of contents
- Exercise 1: Square a Number
- Exercise 2: Check for Even Number
- Exercise 3: String Length Checker
- Exercise 4: Print Message with Log Prefix
- Exercise 5: Concatenate Two Strings
- Exercise 6: Filter Odd Numbers from a List
- Exercise 7: Transform Strings to Uppercase
- Exercise 8: Find First Product Over $100
- Exercise 9: Sort Strings by Length
- Exercise 10: Extract Emails from a User List
- Exercise 11: Check Any Condition
- Exercise 12: Count Specific Elements
- Exercise 13: Custom Object Transformation
- Exercise 14: Group by First Letter
- Exercise 15: Conditional Aggregation
- Exercise 16: Inline Multi-statement Lambda
- Exercise 17: Dictionary Filtering
- Exercise 18: Inline Event Subscription
- Exercise 19: Closure and Captured Variables
- Exercise 20: Inspect an Expression Tree
Exercise 1: Square a Number
Practice Problem: Write a lambda expression assigned to a Func<int, int> that takes an integer and returns its square.
Purpose: This exercise helps you practice assigning a lambda expression to a Func delegate and invoking it like a regular method, a foundational pattern for functional style programming in C#.
Given Input: number = 6
Expected Output:
Number = 6 Square = 36
▼ Hint
- Declare a variable of type
Func<int, int>and assign a lambda expression to it. - The lambda body should multiply the input parameter by itself.
- Call the delegate like a normal method by passing the number in parentheses.
▼ Solution & Explanation
Explanation:
Func<int, int> square = x => x * x;: Declares a delegate that takes anintand returns anint, with the lambda body computing the square.square(number): Invokes the lambda expression by calling the delegate variable as if it were a method.$"Square = {result}": Uses string interpolation to embed the computed result directly in the output text.
Exercise 2: Check for Even Number
Practice Problem: Create a Func<int, bool> lambda that returns true if a given number is even, and false if it is odd.
Purpose: This exercise helps you practice writing a lambda expression that returns a boolean based on a condition, a pattern used constantly in filtering and validation logic.
Given Input: number = 15
Expected Output:
Number = 15 Is Even = False
▼ Hint
Use the modulus operator % inside the lambda body to check whether the remainder of dividing by 2 is zero.
▼ Solution & Explanation
Explanation:
Func<int, bool> isEven = x => x % 2 == 0;: Declares a delegate that takes anintand returns aboolbased on whether the number is divisible by 2.x % 2 == 0: Checks the remainder of dividingxby 2, which is zero only for even numbers.isEven(number): Calls the lambda with the given number and stores the boolean result.
Exercise 3: String Length Checker
Practice Problem: Write a lambda expression that takes a string and an integer, returning true if the string’s length is greater than the integer.
Purpose: This exercise helps you practice writing a lambda expression with two parameters of different types, useful when validating input against a length threshold.
Given Input: word = "Programming", minLength = 5
Expected Output:
Word = Programming Length = 11 Is Longer Than 5 = True
▼ Hint
- Use
Func<string, int, bool>since the lambda takes two input parameters and returns a boolean. - Compare
text.Lengthagainst the passed in length value using the>operator.
▼ Solution & Explanation
Explanation:
Func<string, int, bool>: Declares a delegate with two input parameters, astringand anint, that returns abool.(text, length) => text.Length > length: A multi parameter lambda that compares the string’s length against the given threshold.isLongerThan(word, minLength): Calls the delegate with both arguments in the order they were declared.
Exercise 4: Print Message with Log Prefix
Practice Problem: Create an Action<string> lambda that prepends "[Log]: " to a string and prints it to the console.
Purpose: This exercise helps you practice using the Action delegate for lambdas that perform a side effect, such as printing, rather than returning a value.
Given Input: message = "Application started successfully."
Expected Output: [Log]: Application started successfully.
▼ Hint
Action<string> is used instead of Func because the lambda does not return a value, it only performs an action like printing.
▼ Solution & Explanation
Explanation:
Action<string> logMessage: Declares a delegate that takes astringparameter and returns nothing, suited for operations like printing.message => Console.WriteLine($"[Log]: {message}"): The lambda body prepends the log prefix and writes the combined text to the console.logMessage("Application started successfully."): Invokes the action with the message to be logged.
Exercise 5: Concatenate Two Strings
Practice Problem: Write a lambda expression assigned to a Func<string, string, string> that joins two strings with a space in between.
Purpose: This exercise helps you practice writing a lambda that takes multiple parameters of the same type and returns a combined value, common when building names or formatted text.
Given Input: firstName = "John", lastName = "Smith"
Expected Output: Full Name = John Smith
▼ Hint
Use string interpolation inside the lambda body to place a space between the two parameters, for example $"{first} {second}".
▼ Solution & Explanation
Explanation:
Func<string, string, string>: Declares a delegate that takes twostringparameters and returns astring.(first, second) => $"{first} {second}": The lambda body uses string interpolation to join both parameters with a single space.joinStrings(firstName, lastName): Calls the delegate with the two string values to produce the combined result.
Exercise 6: Filter Odd Numbers from a List
Practice Problem: Given a List<int>, use .Where() with a lambda expression to filter out all odd numbers.
Purpose: This exercise helps you practice using LINQ’s Where() method with a lambda predicate to filter a collection, a common pattern in data processing.
Given Input: numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }
Expected Output:
Odd Numbers: 1 3 5 7 9
▼ Hint
- Call
.Where()on the list and pass a lambda that checksn % 2 != 0. - Chain
.ToList()after.Where()to convert the filtered result back into a list. - Remember to add
using System.Linq;at the top of the file.
▼ Solution & Explanation
Explanation:
numbers.Where(n => n % 2 != 0): Filters the list, keeping only elements where the lambda condition evaluates to true..ToList(): Converts the filtered sequence returned byWhere()into a concreteList<int>.foreach (int num in oddNumbers): Iterates through the filtered list and prints each odd number on its own line.
Exercise 7: Transform Strings to Uppercase
Practice Problem: Given a List<string>, use .Select() with a lambda to convert all strings in the list to uppercase.
Purpose: This exercise helps you practice using LINQ’s Select() method to project each element of a collection into a new transformed value.
Given Input: fruits = { "apple", "banana", "cherry" }
Expected Output:
Uppercase Fruits: APPLE BANANA CHERRY
▼ Hint
- Call
.Select()on the list and pass a lambda that calls.ToUpper()on each string. - Chain
.ToList()after.Select()to materialize the projected sequence into a list.
▼ Solution & Explanation
Explanation:
fruits.Select(f => f.ToUpper()): Projects each string in the list into its uppercase equivalent using the lambda..ToList(): Converts the projected sequence returned bySelect()into a concreteList<string>.foreach (string fruit in upperFruits): Iterates through the transformed list and prints each uppercase fruit name.
Exercise 8: Find First Product Over $100
Practice Problem: Given a list of Product objects (with Name and Price), use .FirstOrDefault() with a lambda to find the first product that costs more than $100.
Purpose: This exercise helps you practice using LINQ’s FirstOrDefault() method with a lambda predicate to search a collection of objects for the first match based on a property value.
Given Input: A list of four products with prices 45.50, 199.99, 25.00, and 899.00.
Expected Output:
Name = Monitor Price = 199.99
▼ Hint
- Define a simple
Productclass withNameandPriceproperties beforeMain(). - Call
.FirstOrDefault()on the list with a lambda that checksp.Price > 100. FirstOrDefault()returnsnullif no match is found, so check fornullbefore printing.
▼ Solution & Explanation
Explanation:
products.FirstOrDefault(p => p.Price > 100): Searches the list and returns the first product whosePriceexceeds 100, ornullif none match.if (firstExpensive != null): Guards against a null reference before accessing the result’s properties.firstExpensive.Name: Accesses theNameproperty of the matchedProductobject for display.
Exercise 9: Sort Strings by Length
Practice Problem: Given a list of strings, use .OrderBy() or .OrderByDescending() with a lambda to sort the list by the length of the strings.
Purpose: This exercise helps you practice using LINQ’s OrderBy() method with a lambda key selector to sort a collection based on a computed value rather than the elements themselves.
Given Input: words = { "kiwi", "banana", "fig", "watermelon", "pear" }
Expected Output:
Sorted by Length: fig kiwi pear banana watermelon
▼ Hint
- Call
.OrderBy()on the list and pass a lambda that returnsw.Lengthas the sort key. - Use
.OrderByDescending()instead if you want the longest strings first.
▼ Solution & Explanation
Explanation:
words.OrderBy(w => w.Length): Sorts the list in ascending order using each string’s length as the key, computed by the lambda..ToList(): Converts the ordered sequence returned byOrderBy()into a concreteList<string>.foreach (string word in sortedWords): Iterates through the sorted list and prints each word in order of increasing length.
Exercise 10: Extract Emails from a User List
Practice Problem: Given a List<User> (with properties Id, Username, Email), use .Select() to extract a list of just the Email strings.
Purpose: This exercise helps you practice using LINQ’s Select() method to project a list of objects down to a single property, a common step when preparing data for display or export.
Given Input: A list of three users, each with an Id, Username, and Email.
Expected Output:
Emails: alice@example.com bob@example.com carol@example.com
▼ Hint
- Define a simple
Userclass withId,Username, andEmailproperties beforeMain(). - Call
.Select()on the list with a lambda that returnsu.Emailfor each user. - Chain
.ToList()to store the projected emails as aList<string>.
▼ Solution & Explanation
Explanation:
users.Select(u => u.Email): Projects eachUserobject down to just itsEmailproperty using the lambda..ToList(): Converts the projected sequence returned bySelect()into a concreteList<string>.foreach (string email in emails): Iterates through the extracted list and prints each email address on its own line.
Exercise 11: Check Any Condition
Practice Problem: Given a list of integers, use .Any() with a lambda to check if the list contains any negative numbers.
Purpose: This exercise helps you practice using LINQ’s Any() method with a lambda predicate to test whether at least one element in a collection satisfies a condition.
Given Input: numbers = { 4, 8, -3, 15, 22, -7 }
Expected Output: Has Negative Number = True
▼ Hint
Call .Any() on the list and pass a lambda that checks whether each number is less than zero, for example n => n < 0.
▼ Solution & Explanation
Explanation:
numbers.Any(n => n < 0): Checks every element against the lambda condition and returnstrueas soon as one negative number is found.- Short circuit:
Any()stops evaluating as soon as it finds a match, making it more efficient than counting all matches.
Exercise 12: Count Specific Elements
Practice Problem: Given a list of strings, use .Count() with a lambda to count how many strings start with the letter ‘A’.
Purpose: This exercise helps you practice using LINQ’s Count() overload that accepts a lambda predicate, letting you count matching elements without writing a manual loop.
Given Input: names = { "Alice", "Bob", "Amanda", "Charlie", "Andrew" }
Expected Output: Names Starting With A = 3
▼ Hint
Use the StartsWith() string method inside the lambda passed to .Count(), for example n => n.StartsWith("A").
▼ Solution & Explanation
Explanation:
names.Count(n => n.StartsWith("A")): Evaluates the lambda against every element and returns the total number of strings for which it returns true.n.StartsWith("A"): Performs a case sensitive check for whether the string begins with the letter A.
Exercise 13: Custom Object Transformation
Practice Problem: Given a List<Employee>, use .Select() with a lambda to project them into an anonymous type containing only FullName (combined FirstName and LastName) and IsSenior (true if YearsOfExperience > 5).
Purpose: This exercise helps you practice projecting objects into a new shape using an anonymous type inside a lambda, a common technique when preparing view specific or report specific data.
Given Input: Three employees with years of experience 3, 8, and 6.
Expected Output:
Sara Khan - Senior: False Tom Reed - Senior: True Nina Patel - Senior: True
▼ Hint
- Inside the lambda passed to
.Select(), usenew { ... }to build an anonymous type with the two computed properties. - Declare the result with
varsince anonymous types do not have a named type you can reference directly. - Combine
FirstNameandLastNamewith string interpolation, and compareYearsOfExperienceto 5 forIsSenior.
▼ Solution & Explanation
Explanation:
new { FullName = ..., IsSenior = ... }: Creates an anonymous type on the fly with only the two properties the lambda needs to produce.var summaries: Usesvarbecause the compiler generated anonymous type has no name that can be written explicitly.e.YearsOfExperience > 5: Computes theIsSeniorflag directly inside the projection instead of storing it as a separate step.
Exercise 14: Group by First Letter
Practice Problem: Given a list of words, use .GroupBy() with a lambda to group the words by their first letter, then print the groups.
Purpose: This exercise helps you practice using LINQ’s GroupBy() method with a lambda key selector to organize a flat collection into related buckets.
Given Input: words = { "apple", "avocado", "banana", "blueberry", "cherry" }
Expected Output:
a: apple, avocado b: banana, blueberry c: cherry
▼ Hint
- Call
.GroupBy()with a lambda that returns the first character of each word as the grouping key. - Each resulting group has a
Keyproperty and can itself be enumerated like a list. - Use
string.Join(", ", group)to combine the words in a group into a single readable line.
▼ Solution & Explanation
Explanation:
words.GroupBy(w => w[0]): Groups the words using the first character of each string as the key, computed by the lambda.group.Key: Holds the shared first letter for all words inside that particular group.string.Join(", ", group): Concatenates all the words within a group into a single comma separated line.
Exercise 15: Conditional Aggregation
Practice Problem: Given a List<Order> (with Amount and IsPaid), use .Sum() with a lambda to calculate the total revenue generated only from paid orders.
Purpose: This exercise helps you practice using LINQ’s Sum() method with a lambda that applies conditional logic inline, avoiding a separate filter step before aggregating.
Given Input: Four orders with amounts 120.50, 75.00, 200.00, and 40.25, where the first and third are marked paid.
Expected Output: Total Paid Revenue = 320.5
▼ Hint
- Use the ternary operator inside the lambda to return
o.Amountwheno.IsPaidis true, and0otherwise. .Sum()adds up whatever value the lambda returns for each element in the list.
▼ Solution & Explanation
Explanation:
orders.Sum(o => o.IsPaid ? o.Amount : 0): Adds each order’sAmountto the running total only whenIsPaidis true, contributing zero otherwise.o.IsPaid ? o.Amount : 0: A ternary expression that acts as an inline filter within the aggregation itself.
Exercise 16: Inline Multi-statement Lambda
Practice Problem: Write a Func<int, int, int> using a statement block { ... } that compares two numbers, logs the larger number to the console, and then returns the absolute difference between them.
Purpose: This exercise helps you practice writing a statement lambda that contains multiple lines of logic instead of a single expression, useful when a lambda needs to perform a side effect before returning a value.
Given Input: first = 18, second = 42
Expected Output:
Larger Number = 42 Absolute Difference = 24
▼ Hint
- A statement lambda wraps its body in curly braces and requires an explicit
returnstatement. - Use the ternary operator to determine the larger value before printing it.
- Use
Math.Abs()on the subtraction of the two numbers to compute the absolute difference.
▼ Solution & Explanation
Explanation:
(a, b) => { ... }: A statement lambda with a curly brace body, allowing multiple statements before the finalreturn.Console.WriteLine($"Larger Number = {larger}"): Executes a side effect inside the lambda before the return statement runs.Math.Abs(a - b): Computes the absolute difference regardless of which of the two numbers is larger.
Exercise 17: Dictionary Filtering
Practice Problem: Given a Dictionary<string, int> representing items and their stock counts, use LINQ and a lambda to filter out items that are out of stock (count == 0).
Purpose: This exercise helps you practice applying LINQ’s Where() method to a dictionary, where each element is a KeyValuePair and the lambda inspects the Value to decide what stays.
Given Input: A dictionary with Keyboard: 12, Mouse: 0, Monitor: 5, Webcam: 0.
Expected Output:
In Stock Items: Keyboard: 12 Monitor: 5
▼ Hint
- Call
.Where()directly on the dictionary, since it can be enumerated as a sequence ofKeyValuePair<string, int>entries. - Inside the lambda, check
item.Value > 0to keep only items that still have stock. - Access
item.Keyanditem.Valuewhen printing each remaining entry.
▼ Solution & Explanation
Explanation:
stock.Where(item => item.Value > 0): Filters the dictionary entries, keeping only those whose stock count is greater than zero.item.Keyanditem.Value: Access the item name and its remaining stock count from eachKeyValuePair.
Exercise 18: Inline Event Subscription
Practice Problem: Given a custom class with an public event EventHandler ThresholdReached, use a lambda expression to subscribe to the event and print a message when it fires.
Purpose: This exercise helps you practice subscribing to an event using a lambda instead of a separately declared method, which keeps small event handlers close to where they are used.
Given Input: temperature = 105
Expected Output: Warning: Temperature threshold reached!
▼ Hint
- Use
+=to subscribe a lambda directly to the event, matching theEventHandlersignature of(sender, e). - Use the null conditional operator
?.Invoke()when raising the event, so nothing happens if no one has subscribed.
▼ Solution & Explanation
Explanation:
sensor.ThresholdReached += (sender, e) => ...: Subscribes a lambda directly to the event without declaring a separate named method.ThresholdReached?.Invoke(this, EventArgs.Empty): Raises the event, running every subscribed lambda, but only if at least one subscriber exists.if (temperature > 100): Determines whether the threshold condition is met before the event is raised.
Exercise 19: Closure and Captured Variables
Practice Problem: Create a method that returns a Func<int, int>. Inside the method, capture a local variable factor. The returned lambda should multiply its input by factor. Demonstrate how changing factor after defining the lambda affects the outcome.
Purpose: This exercise helps you practice closures, where a lambda captures a variable from its enclosing scope and keeps a reference to it even after the method that created it has returned.
Given Input: factor = 3, later reassigned to factor = 10
Expected Output:
5 multiplied by factor = 15 5 multiplied by factor after change = 15
▼ Hint
- Write a method that takes
factoras a parameter and returns a lambda referencing that parameter. - The lambda captures the
factorparameter belonging to that specific method call, not the outer variable used to call the method. - Reassigning the outer
factorvariable inMain()after the lambda is created has no effect on the already returned lambda.
▼ Solution & Explanation
Explanation:
return number => number * factor;: The returned lambda forms a closure over thefactorparameter ofCreateMultiplier, keeping it alive after the method returns.CreateMultiplier(factor): Passes the value of the outerfactorat the time of the call, which becomes a separate copy inside the method.- Unaffected by reassignment: Setting
factor = 10inMain()only changes the outer local variable, not the copy captured insideCreateMultiplier, so the lambda still multiplies by 3.
Exercise 20: Inspect an Expression Tree
Practice Problem: Instead of Func<int, bool>, assign a lambda expression to an Expression<Func<int, bool>> that checks if a number is greater than 5. Write a small script to parse and print the node types of the expression tree.
Purpose: This exercise helps you practice the difference between a compiled lambda delegate and an expression tree, which represents the lambda as inspectable data rather than executable code, a technique used by LINQ providers such as Entity Framework.
Given Input: isGreaterThanFive = number => number > 5
Expected Output:
Expression = number => (number > 5) Body Node Type = GreaterThan Left Node Type = Parameter Right Node Type = Constant
▼ Hint
- Add
using System.Linq.Expressions;so theExpression<T>type and related classes are available. - An
Expression<Func<int, bool>>is not compiled automatically, it stays as a tree describing the logic, accessible through itsBody. - Cast
BodytoBinaryExpressionto inspect itsLeftandRightsub expressions and theirNodeType.
▼ Solution & Explanation
Explanation:
Expression<Func<int, bool>>: Stores the lambda as a tree of expression objects instead of compiling it directly into executable code.isGreaterThanFive.Body: Represents the root of the expression tree, in this case the greater than comparison.(BinaryExpression)isGreaterThanFive.Body: Casts the body so itsLeftandRightoperands, the parameter and the constant 5, can be inspected individually.

Leave a Reply