LINQ offers various methods to transform and shape data, making it a versatile tool for developers. In this blog post, we’ll explore the SelectMany method and learn how it can be used to work with nested collections, flatten data structures, and perform advanced data manipulations.
Understanding the SelectMany Method
The SelectMany method is a powerful operator that is used to flatten nested collections and perform complex data manipulations in C#. It allows you to work with collections of collections and project them into a single, flattened sequence.
The SelectMany method takes two parameters: the source collection and a selector function. The selector function takes an element from the source collection and returns an enumerable collection of elements. The SelectMany method then flattens these enumerable collections into a single output sequence. In other words, it merges multiple collections into one.
Here is the basic syntax of the SelectMany method:
1 2 3 4 5 6 7 |
IEnumerable<TResult> SelectMany<TSource, TResult>( IEnumerable<TSource> source, Func<TSource, IEnumerable<TResult>> selector ) |
source
: The source collection on which the SelectMany method is applied.selector
: A delegate function that defines the projection to be applied to each element of the source collection. It takes an element from the source collection and returns an enumerable collection of elements.- The result of the SelectMany method is an
IEnumerable<TResult>
, whereTResult
is the type of elements in the flattened sequence.
One of the most common use cases for the SelectMany method is flattening nested collections. Let’s consider an example where we have a collection of objects, each containing another collection of items.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
public class Order { public int OrderId { get; set; } public List<Product> Products { get; set; } } public class Product { public int ProductId { get; set; } public string Name { get; set; } } List<Order> orders = GetOrders(); // Assume this method returns a list of orders IEnumerable<Product> allProducts = orders.SelectMany(order => order.Products); |
In the above example, the SelectMany method is used to flatten the nested Products
collection within each Order
object. The result is an enumerable sequence of all the products across all orders.
LINQ SelectMany Projection Method
Here, you can see that the SelectMany method returns an IEnumerable<char>. This is because the SelectMany method returns all the elements from the sequence. Here the nameList is the sequence or collection or the data source. And the sequence contains two strings. And we know the string is a collection of characters. So, the SelectMany method fetches all the characters from the above two strings and then converts them into one sequence i.e. IEnumerable<char>.
1 2 3 4 5 6 7 8 9 10 11 12 |
static void Main(string[] args) { List<string> nameList =new List<string>(){"Sanaya", "Aairah" }; IEnumerable<char> methodSyntax = nameList.SelectMany(x => x); foreach(char c in methodSyntax) { Console.Write(c + " "); } Console.ReadKey(); } |
LINQ SelectMany Using Query Syntax
The most important point that you need to remember is there is no such SelectMany Operator available in LINQ to write Query Syntax. In the below example, we are fetching all the strings from the nameList collection to str object and then we are using another from clause to fetch all the characters from the str object and then we are projecting the characters which are going to contain all the characters available in both strings.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
static void Main(string[] args) { List<string> nameList =new List<string>(){"Sanaya", "Aairah" }; IEnumerable<char> querySyntax = from str in nameList from ch in str select ch; foreach (char c in querySyntax) { Console.Write(c + " "); } Console.ReadKey(); } |
SelectMany Projection Method with Complex Data Type
Let us create a class file with the name Student.cs and then copy and paste the following code into it. As you can see, we have created the following Student class with four properties. Further, if you notice the Programming property of the Student class returns List<string>. Here we have also created one method which will return the List of students which will be going to act as our data source.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
public class Student { public int ID { get; set; } public string Name { get; set; } public string Email { get; set; } public List<string> Programming { get; set; } public static List<Student> GetStudents() { return new List<Student>() { new Student(){ID = 1, Name = "Sanaya", Email = "samaya@example.com", Programming = new List<string>() { "C#", "Jave", "C++"} }, new Student(){ID = 2, Name = "Ahmed", Email = "ahmed@example.com", Programming = new List<string>() { "WCF", "SQL Server", "C#" }}, new Student(){ID = 3, Name = "Aairah", Email = "aairah@example.com", Programming = new List<string>() { "MVC", "Jave", "LINQ"} }, new Student(){ID = 4, Name = "Saba", Email = "saba@example.com", Programming = new List<string>() { "ADO.NET", "C#", "LINQ" } } }; } } |
The complete example code is given below. In the below example, I am showing both LINQ Query Syntax and Method Syntax to achieve the same.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
static void Main(string[] args) { //Using Method Syntax List<string> MethodSyntax = Student.GetStudents().SelectMany(std => std.Programming).ToList(); //Using Query Syntax IEnumerable<string> QuerySyntax = from std in Student.GetStudents() from program in std.Programming select program; //Printing the values foreach (string program in MethodSyntax) { Console.WriteLine(program); } Console.ReadKey(); } |
When we execute the program, it will give us the following output. Here, you can see, it contains all the programming strings from all the students. Also, if you notice it is also containing the same string multiple times.
Remove Duplicates while using LINQ SelectMany Method
If you notice, in our previous example, we get the output as expected but with duplicate program names. If you want only the distinct program names then you need to apply the distinct method on the result set which is shown in the below examples. The LINQ Distinct Method is going to return distinct elements from a sequence by using the default equality comparer to compare values. In our upcoming articles, we will discuss Comparer and the Distinct Method in detail. For now, just remember distinct method is going to return distinct elements from a sequence.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
static void Main(string[] args) { //Using Method Syntax List<string> MethodSyntax = Student.GetStudents() .SelectMany(std => std.Programming) .Distinct() .ToList(); //Using Query Syntax IEnumerable<string> QuerySyntax = (from std in Student.GetStudents() from program in std.Programming select program).Distinct().ToList(); //Printing the values foreach (string program in QuerySyntax) { Console.WriteLine(program); } Console.ReadKey(); } |
LINQ SelectMany Method
Now, let us proceed and see more complex examples to understand the LINQ SelectMany Method. Our requirement is to retrieve the student’s name along with the program language names. The following example exactly does the same. For this, we are going to use the other overloaded version of the SelectMany method. In the below example, I am showing both Query and Method Syntax to achieve the same.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
static void Main(string[] args) { //Using Method Syntax var MethodSyntax = Student.GetStudents() .SelectMany(std => std.Programming, (student, program) => new { StudentName = student.Name, ProgramName = program } ) .ToList(); //Using Query Syntax var QuerySyntax = (from std in Student.GetStudents() from program in std.Programming select new { StudentName = std.Name, ProgramName = program }).ToList(); //Printing the values foreach (var item in QuerySyntax) { Console.WriteLine(item.StudentName + " => " + item.ProgramName); } Console.ReadKey(); } |
The SelectMany method is a valuable tool in the LINQ toolbox that allows you to work with nested collections and perform advanced data manipulations. By leveraging the power of SelectMany, you can flatten data structures, extract information from nested collections, and combine it with other LINQ operators to create powerful queries.
Remember to experiment with different scenarios and explore the capabilities of the SelectMany method. It can help you write more concise, expressive, and efficient code when working with collections in C#. Happy coding!
Leave a Comment