In previous article, I mentioned Format Code in Visual Studio (With Indentation) but in this article, I have mentioned Select vs SelectMany in C# With an Example.
Select and SelectMany, both are projection operators.
- Select: It selects value from collection.
- SelectMany: It selects value from collection or collections, or we can say it performs cross join operation in SQL where it takes the cross product.
Select operator produces one result value for every source value while SelectMany produces a single result from multiple or nested collection and flatten the result.
Let's take a look at an example to understand difference between Select and SelectMany.
First we can define a Customer class with list of strings with their contact numbers:
class Customer
{
public string Name { get; set; }
public string Title { get; set; }
public List<string> ContactNumbers { get; set; }
}
Then create 3 customers for selection
List<Customer> customers = new List<Customer>() {
new Customer { Name = "Ian", Title = "Mr", ContactNumbers = new List<string> { "45521152", "90555236", "9855215" } },
new Customer { Name = "Alfred", Title = "Mr", ContactNumbers = new List<string> { "12556661", "15556731" } },
new Customer { Name = "Lilly", Title = "Mrs", ContactNumbers = new List<string> { "3678452"} }
};
We have 3 customers and 6 contact number.
Let’s write get each contact number with traditional way by looping each item.
using System;
using System.Linq;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
List<Customer> customers = new List<Customer>() {
new Customer { Name = "Ian", Title = "Mr", ContactNumbers = new List<string> { "45521152", "90555236", "9855215" } },
new Customer { Name = "Alfred", Title = "Mr", ContactNumbers = new List<string> { "12556661", "15556731" } },
new Customer { Name = "Lilly", Title = "Mrs", ContactNumbers = new List<string> { "3678452"} }
};
foreach (var customer in customers)
{
foreach (var number in customer.ContactNumbers)
{
Console.WriteLine($"{number}");
}
}
Console.ReadKey();
}
public class Customer
{
public string Name { get; set; }
public string Title { get; set; }
public List<string> ContactNumbers { get; set; }
}
}
Output:
As you can see from above code and output, we were able to get all contacts, but We have to use double foreach loop to achieve this.
Let’s try using Select()
to achieve the same result!
using System;
using System.Linq;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
List<Customer> customers = new List<Customer>() {
new Customer { Name = "Ian", Title = "Mr", ContactNumbers = new List<string> { "45521152", "90555236", "9855215" } },
new Customer { Name = "Alfred", Title = "Mr", ContactNumbers = new List<string> { "12556661", "15556731" } },
new Customer { Name = "Lilly", Title = "Mrs", ContactNumbers = new List<string> { "3678452"} }
};
//add this line of code
IEnumerable<List<string>> contactNumbers = customers.Select(x => x.ContactNumbers);
foreach (var numbers in contactNumbers)
{
foreach (var number in numbers)
{
Console.WriteLine($"{number}");
}
}
Console.ReadKey();
}
public class Customer
{
public string Name { get; set; }
public string Title { get; set; }
public List<string> ContactNumbers { get; set; }
}
}
Output:
45521152
90555236
9855215
12556661
15556731
3678452
Still the same result and we have used double foreach
again! Select method provides projection.
When we Select(x=> x.ContractNumbers)
, first it took the source object which is "Mr.Ian".
It adds Mr.Ian to list’s first item then, add each ContactNumbers to the first item as List.
Select()
made a projection with the given property name per source object!
But there is still double foreach.
Let’s try SelectMany()
and see if we can flatten these lists. In the end we just need a List of Contract numbers right?
static void Main(string[] args)
{
List<Customer> customers = new List<Customer>() {
new Customer { Name = "Ian", Title = "Mr", ContactNumbers = new List<string> { "45521152", "90555236", "9855215" } },
new Customer { Name = "Alfred", Title = "Mr", ContactNumbers = new List<string> { "12556661", "15556731" } },
new Customer { Name = "Lilly", Title = "Mrs", ContactNumbers = new List<string> { "3678452"} }
};
//add select many
IEnumerable<string> contactNumbers = customers.SelectMany(x => x.ContactNumbers);
//use single foreach
foreach (var numbers in contactNumbers)
{
Console.WriteLine($"{numbers}");
}
Console.ReadKey();
}
We have just used SelectMany with the same projection property which is "ContractNumbers".
We need contract numbers in a single list from every source.
Yes! SelectMany()
has combined results to a single list for every contract number for every source.
You may also like to read:
Lambda expression in C# (With Examples)
Foreach() vs Parallel.Foreach() in C#