Recursive pattern matching helps you check complex data step-by-step by breaking it down into smaller parts. It makes your code easier to read and understand when working with nested or linked data.
Recursive pattern matching in C Sharp (C#)
public class Node<T> { public T Value { get; set; } public Node<T>? Next { get; set; } public Node(T value, Node<T>? next = null) { Value = value; Next = next; } } public static bool ContainsValue<T>(Node<T>? node, T target) where T : IEquatable<T> { return node switch { null => false, // base case: empty list { Value: var value, Next: var next } when value.Equals(target) => true, // found value { Next: var next } => ContainsValue(next, target), // recursive call _ => false }; }
The switch expression is used to match the shape of the data recursively.
Null is the base case to stop recursion.
ContainsValue<int>(null, 5) // returns false
var singleNode = new Node<int>(10); ContainsValue(singleNode, 10) // returns true
var list = new Node<int>(1, new Node<int>(2, new Node<int>(3))); ContainsValue(list, 3) // returns true
var list = new Node<int>(1, new Node<int>(2, new Node<int>(3))); ContainsValue(list, 4) // returns false
This program creates a linked list of integers and uses recursive pattern matching to check if certain values exist in the list. It prints the list before searching and shows the results of the searches.
using System; public class Node<T> { public T Value { get; set; } public Node<T>? Next { get; set; } public Node(T value, Node<T>? next = null) { Value = value; Next = next; } } public class Program { public static bool ContainsValue<T>(Node<T>? node, T target) where T : IEquatable<T> { return node switch { null => false, { Value: var value, Next: var next } when value.Equals(target) => true, { Next: var next } => ContainsValue(next, target), _ => false }; } public static void PrintList<T>(Node<T>? node) { if (node == null) { Console.WriteLine("List is empty."); return; } Console.Write("List values: "); Node<T>? current = node; while (current != null) { Console.Write(current.Value + " "); current = current.Next; } Console.WriteLine(); } public static void Main() { var list = new Node<int>(5, new Node<int>(10, new Node<int>(15))); Console.WriteLine("Before searching:"); PrintList(list); int searchValue1 = 10; Console.WriteLine($"Does the list contain {searchValue1}? {ContainsValue(list, searchValue1)}"); int searchValue2 = 20; Console.WriteLine($"Does the list contain {searchValue2}? {ContainsValue(list, searchValue2)}"); } }
Time complexity is O(n) because it may check each node once.
Space complexity is O(n) due to recursive calls on the call stack.
Common mistake: forgetting the base case (null) causes infinite recursion.
Use recursive pattern matching when data is naturally recursive, like linked lists or trees. For flat data, simple loops may be better.
Recursive pattern matching breaks down data step-by-step to check or process it.
It uses a base case to stop recursion and matches data shapes with switch expressions.
This technique is great for linked lists, trees, and nested data structures.
Practice
Solution
Step 1: Understand recursive pattern matching concept
Recursive pattern matching is used to analyze data by breaking it down into smaller parts recursively.Step 2: Identify the purpose from options
To break down complex data structures step-by-step correctly states that it breaks down complex data structures step-by-step, which matches the concept.Final Answer:
To break down complex data structures step-by-step -> Option AQuick Check:
Recursive pattern matching = step-by-step data breakdown [OK]
- Confusing recursion with infinite loops
- Thinking it declares variables
- Assuming it handles exceptions
Solution
Step 1: Recall C# recursive pattern syntax
In C#, recursive patterns use parentheses with variables inside, likeNode(var value, var next).Step 2: Compare options to correct syntax
case Node(var value, var next): matches the correct syntax. Other options use invalid symbols like brackets or arrows.Final Answer:
case Node(var value, var next): -> Option AQuick Check:
Recursive pattern syntax uses parentheses ( ) [OK]
- Using square brackets instead of parentheses
- Using arrows or semicolons incorrectly
- Missing 'var' keyword before variables
record Node(int Value, Node? Next);
Node list = new(1, new(2, new(3, null)));
string PrintList(Node? node) => node switch
{
null => "End",
Node(var v, var n) => $"{v} -> " + PrintList(n)
};
Console.WriteLine(PrintList(list));
Solution
Step 1: Understand the recursive function PrintList
PrintList prints the current node's value, then calls itself on the next node, until it reaches null and returns "End".Step 2: Trace the output for list nodes 1, 2, 3
It prints "1 -> " + PrintList(2), then "2 -> " + PrintList(3), then "3 -> " + PrintList(null), which returns "End".Final Answer:
1 -> 2 -> 3 -> End -> Option CQuick Check:
Recursive print with null base case = 1 -> 2 -> 3 -> End [OK]
- Ignoring the base case output
- Missing arrows in output
- Confusing spaces with arrows
record Node(int Value, Node? Next);
string PrintList(Node? node) => node switch
{
Node(var v, var n) => $"{v} -> " + PrintList(n),
null => "End"
};
Solution
Step 1: Check switch expression order and syntax
In C#, switch expressions check patterns top to bottom. Here, 'Node' pattern matches non-null nodes, and 'null' matches null nodes. The order is valid.Step 2: Verify syntax correctness
The pattern syntax and semicolons are correct. No syntax errors exist.Final Answer:
No error, code works correctly -> Option BQuick Check:
Pattern order and syntax are valid [OK]
- Thinking null must come first
- Assuming missing semicolon error
- Misreading pattern syntax
record TreeNode(int Value, TreeNode? Left, TreeNode? Right);
Write a recursive pattern matching expression to calculate the sum of all values in the tree. Which of the following switch expressions correctly implements this?
Solution
Step 1: Understand the tree structure and sum logic
The tree node has three parts: Value, Left, and Right. The sum should add the current value plus sums of left and right subtrees.Step 2: Check each option for correct pattern and order
node switch { null => 0, TreeNode(var v, var l, var r) => v + Sum(l) + Sum(r) } correctly matches null first (base case) and then TreeNode with three variables (value, left, right). It sums value + Sum(left) + Sum(right). node switch { TreeNode(v, l, r) => v + Sum(l) + Sum(r), null => 0 } misses 'var' keywords, which is required. node switch { null => 0, TreeNode(v, l, r) => v + Sum(l) + Sum(r) } misses 'var' keywords, which is required. node switch { null => 0, TreeNode(var v, var l) => v + Sum(l) } misses the right subtree.Final Answer:
node switch { null => 0, TreeNode(var v, var l, var r) => v + Sum(l) + Sum(r) } -> Option DQuick Check:
Correct pattern with all parts and base case first [OK]
- Omitting 'var' in pattern variables
- Missing one subtree in sum
- Placing null case after non-null without care
Ready to prove it?
Pass the test and this pattern moves unknown
