Custom LINQ extension methods in C Sharp (C#) - Time & Space Complexity
When we create custom LINQ extension methods, we want to know how their speed changes as the input list grows.
We ask: How many steps does the method take when the list gets bigger?
Analyze the time complexity of the following code snippet.
public static IEnumerable<T> CustomWhere<T>(this IEnumerable<T> source, Func<T, bool> predicate)
{
foreach (var item in source)
{
if (predicate(item))
yield return item;
}
}
This method filters items from a list based on a condition, returning only those that match.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Looping through each item in the input list once.
- How many times: Exactly once for every item in the list.
As the list gets bigger, the method checks each item one by one.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 10 checks |
| 100 | About 100 checks |
| 1000 | About 1000 checks |
Pattern observation: The number of steps grows directly with the size of the list.
Time Complexity: O(n)
This means the time to finish grows in a straight line as the list gets bigger.
[X] Wrong: "The method runs faster because it stops early when it finds a match."
[OK] Correct: The method still checks every item because it must find all matches, not just one.
Understanding how your custom LINQ methods scale helps you write efficient code and explain your thinking clearly in interviews.
"What if we changed the method to use nested loops to compare each item with every other item? How would the time complexity change?"
Practice
Solution
Step 1: Understand extension method structure
Extension methods must be static methods inside static classes.Step 2: Identify the special parameter usage
The first parameter must have thethiskeyword to specify the type it extends.Final Answer:
It must be a static method inside a static class withthison the first parameter. -> Option AQuick Check:
Extension method = static + static class + this param [OK]
- Making the method non-static
- Forgetting the static class container
- Omitting the 'this' keyword on the first parameter
IsEven for IEnumerable<int>?Solution
Step 1: Check method modifiers and parameters
The method must be public static and havethisbefore the first parameter to be an extension method.Step 2: Verify the parameter type and method signature
public static bool IsEven(this IEnumerable<int> source) { ... } correctly usesthis IEnumerable<int> sourceand is static and public.Final Answer:
public static bool IsEven(this IEnumerable<int> source) { ... } -> Option AQuick Check:
Extension method syntax = public static + this param [OK]
- Missing 'this' keyword on the first parameter
- Not making the method static
- Incorrect access modifier
public static IEnumerable<int> GetPositive(this IEnumerable<int> source) {
foreach (var num in source) {
if (num > 0) yield return num;
}
}
var numbers = new List<int> { -1, 0, 3, 5, -2 };
var result = numbers.GetPositive().ToList();
Console.WriteLine(string.Join(",", result));Solution
Step 1: Understand the extension method logic
The method yields only numbers greater than zero from the source list.Step 2: Apply the method to the list
From the list [-1, 0, 3, 5, -2], only 3 and 5 are greater than zero and yielded.Final Answer:
3,5 -> Option DQuick Check:
Filter positive numbers = 3,5 [OK]
- Including zero as positive
- Returning all numbers without filtering
- Confusing yield return with return
public static IEnumerable<int> FilterEven(IEnumerable<int> source) {
foreach (var num in source) {
if (num % 2 == 0) yield return num;
}
}Solution
Step 1: Check extension method signature
The method lacks thethiskeyword on the first parameter, so it is not an extension method.Step 2: Verify other syntax elements
Usingyield returninside a foreach is valid, and '%' is a valid operator in C#.Final Answer:
Missing 'this' keyword on the first parameter to make it an extension method. -> Option CQuick Check:
Extension method requires 'this' on first parameter [OK]
- Forgetting 'this' keyword
- Thinking 'yield return' is invalid in loops
- Misunderstanding the modulo operator
ToDictionaryByLength that converts an IEnumerable<string> into a Dictionary<int, List<string>>, grouping strings by their length. Which implementation correctly achieves this?Solution
Step 1: Understand grouping by length
We need to group strings by their length, so GroupBy with key s.Length is correct.Step 2: Convert groups to dictionary
Use ToDictionary with group key and list of strings as value.Step 3: Check other options
public static Dictionary ToDictionaryByLength(IEnumerable<string> source) { return source.ToDictionary(s => s.Length, s => new List<string> { s }); } does not group; it tries to create dictionary with duplicate keys causing error. public static Dictionary ToDictionaryByLength(this IEnumerable<string> source) { var dict = new Dictionary(); foreach (var s in source) { dict[s.Length] = new List<string> { s }; } return dict; } overwrites values instead of adding to list. public static Dictionary ToDictionaryByLength(this IEnumerable<string> source) { return source.ToDictionary(s => s.Length, s => s); } tries to map to string instead of list.Final Answer:
public static Dictionary<int, List<string>> ToDictionaryByLength(this IEnumerable<string> source) { return source.GroupBy(s => s.Length) .ToDictionary(g => g.Key, g => g.ToList()); } -> Option BQuick Check:
GroupBy + ToDictionary with list = correct grouping [OK]
- Not grouping before ToDictionary
- Overwriting dictionary entries instead of adding to list
- Returning wrong value types in dictionary
Ready to prove it?
Pass the test and this pattern moves unknown
