C# tutorials > Modern C# Features > C# 6.0 and Later > What are list patterns in C# 11 and how can you use them for matching?
What are list patterns in C# 11 and how can you use them for matching?
C# 11 introduced list patterns, a powerful feature for matching sequences of elements within collections like arrays and lists. List patterns allow you to examine the structure and content of these collections in a concise and expressive way using pattern matching syntax. This tutorial will explore how to use list patterns effectively for various matching scenarios.
Basic List Pattern Matching
This example demonstrates the simplest form of list pattern matching. The is
operator, combined with the list pattern syntax [element1, element2, ...]
, checks if the array numbers
matches the specified sequence. The _
(discard pattern) is used to match any element at that position.
using System;
public class ListPatternExample
{
public static void Main(string[] args)
{
int[] numbers = { 1, 2, 3, 4, 5 };
if (numbers is [1, 2, 3, 4, 5])
{
Console.WriteLine("The array is exactly {1, 2, 3, 4, 5}");
}
if (numbers is [1, _, 3, _, 5])
{
Console.WriteLine("The array starts with 1, then any value, then 3, then any value, and ends with 5.");
}
}
}
Using Slice Patterns
Slice patterns (..
) allow you to match a sequence of zero or more elements. In the first if
statement, we check if the array starts with 1, 2 and ends with 5, irrespective of the number of elements in between. The second if
statement checks if the array ends with 4, 5. Slice patterns are very powerful for checking prefixes, suffixes, and contents regardless of overall length.
using System;
public class ListPatternExample
{
public static void Main(string[] args)
{
int[] numbers = { 1, 2, 3, 4, 5 };
if (numbers is [1, 2, .., 5])
{
Console.WriteLine("The array starts with 1, 2 and ends with 5, with any number of elements in between.");
}
if (numbers is [.., 4, 5])
{
Console.WriteLine("The array ends with 4, 5, with any number of elements before them.");
}
}
}
Capturing Elements with List Patterns
You can capture elements matched by list patterns into variables using the var
keyword (or explicitly typed variables). This allows you to access the matched values within the if
block. Here, we capture the first, third and last elements of the array into first
, third
, and last
respectively.
using System;
public class ListPatternExample
{
public static void Main(string[] args)
{
int[] numbers = { 1, 2, 3, 4, 5 };
if (numbers is [var first, _, var third, .., var last])
{
Console.WriteLine($"First: {first}, Third: {third}, Last: {last}");
}
}
}
Type Patterns within List Patterns
List patterns support type patterns, allowing you to match elements based on their type. In this example, we are checking if the mixed
array contains an int
, a string
, a double
, another int
, and finally another string
. If the types match, the values are captured in the variables a
, b
, c
, and d
.
using System;
public class ListPatternExample
{
public static void Main(string[] args)
{
object[] mixed = { 1, "hello", 3.14, 4, "world" };
if (mixed is [int a, string b, double _, int c, string d])
{
Console.WriteLine($"a: {a}, b: {b}, c: {c}, d: {d}");
}
}
}
Nested List Patterns
List patterns can be nested to match multi-dimensional arrays or lists of lists. This example checks if the matrix
array is exactly [[1, 2], [3, 4]]
.
using System;
public class ListPatternExample
{
public static void Main(string[] args)
{
int[][] matrix = { new int[] { 1, 2 }, new int[] { 3, 4 } };
if (matrix is [[1, 2], [3, 4]])
{
Console.WriteLine("The matrix is exactly [[1, 2], [3, 4]]");
}
}
}
Concepts Behind the Snippet
The core concept behind list patterns is structural matching. It allows you to deconstruct a sequence and match its elements against a predefined pattern. The is
operator combined with list patterns provides a declarative and readable way to express complex matching logic. Key components include:
Real-Life Use Case
List patterns are useful in scenarios such as: Imagine you're parsing a command line input. You could use a list pattern to ensure the input starts with a specific command and then extract the required arguments.
Best Practices
When using list patterns:
Interview Tip
When discussing list patterns in an interview, be prepared to explain: Demonstrate your understanding by providing clear and concise examples.
var
.
When to use them
Use list patterns when you need to: However, if you only need to check for the existence of a single element or a simple condition, other methods like
Any()
or Contains()
might be more appropriate.
Memory footprint
List patterns themselves don't directly allocate significant memory. The primary memory usage comes from the underlying data structures you are matching against (arrays, lists, etc.). However, be mindful of memory implications when capturing elements into new variables. Each captured element will require memory to store its value. If you're dealing with very large collections, consider whether you truly need to capture all matched elements or if you can process them directly within the matching block.
Alternatives
Alternatives to list patterns include: List patterns often provide a more concise and readable solution compared to these alternatives, especially for complex matching scenarios. The best choice depends on the specific requirements and complexity of the task.
for
or foreach
loops with index-based access to elements.Where()
, Select()
, First()
, etc., to filter and transform sequences.
Pros
Advantages of using list patterns:
Cons
Disadvantages of using list patterns:
FAQ
-
Can I use list patterns with `IEnumerable
`?
Yes, list patterns can be used with any type that implements theIEnumerable
interface, including arrays, lists, and other collections. However, the underlying type needs to be known at compile time to deconstruct the sequence using the pattern. For example you cannot use list pattern directly with `IEnumerable -
What happens if the list pattern doesn't match?
If the list pattern doesn't match, theis
operator returnsfalse
, and the code block associated with the pattern is not executed. You can use anelse
block to handle the case where the pattern doesn't match. -
Are list patterns efficient?
List patterns are generally efficient, but performance can vary depending on the complexity of the pattern and the size of the input sequence. For performance-critical scenarios, it's recommended to benchmark your code to ensure that list patterns are the most efficient solution.