SelectMany operator is used when we have a sequence of objects which has a collection property and we need to enumerate each item of child collection one by one.
SelectMany operator comes under Projection operators category of LINQ Query Operators.
Below is the syntax of SelectMany operator
public static IEnumerable<TResult> SelectMany<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, IEnumerable<TResult>> selector);
public static IEnumerable<TResult> SelectMany<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, int, IEnumerable<TResult>> selector);
public static IEnumerable<TResult> SelectMany<TSource, TCollection, TResult>(this IEnumerable<TSource> source, Func<TSource, IEnumerable<TCollection>> collectionSelector, Func<TSource, TCollection, TResult> resultSelector);
There are three main overloads of SelectMany operator. Below are the usage of above overload methods.
- First overload is used to select collection property of target object.
- Second overload is used to select collection property of target object and it also provides the index of each object. For example, it provides index 0 for first item of sequence and index 1 for second item of sequence.
- Third overload provides very useful functionality. In addition to above, it also provides a custom function which we can use to create anonymous types and return that anonymous type in the result.
Let’s see all overload examples below:
C# LINQ SelectMany Examples
We have an employee object and employee object has a list of department collection.
public class Employee
{
public int ID { get; set; }
public List<Department> Departments { get; set; }
}
public class Department
{
public string Name { get; set; }
}
public static void Main(string[] args)
{
List<Employee> employees = new List<Employee>();
employees.Add(new Employee
{
ID = 1,
Name = "Kapil",
Departments = new List<Department>()
{
new Department { Name = "Marketing" },
new Department { Name = "Sales"}
}
});
employees.Add(new Employee
{
ID = 2,
Name = "Raj",
Departments = new List<Department>()
{
new Department { Name = "Advertisement" },
new Department { Name = "Production"}
}
});
employees.Add(new Employee
{
ID = 3,
Name = "Ramesh",
Departments = new List<Department>()
{
new Department { Name = "Production" },
new Department { Name = "Sales"}
}
});
}
First Overload SelectMany Operator
In this problem scenario, we need to print each department name which are associated with each employee. In this case we need to use first overload of SelectMany operator.
var result = employees.SelectMany(w => w.Departments);
foreach(var dept in result)
{
Console.WriteLine(dept.Name);
}
Marketing
Sales
Advertisement
Production
Production
Sales
Second Overload SelectMany Operator
In this problem scenario, we need to print each department name plus index value of each object of a sequence.
var result = employees.SelectMany((w, index) => w.Departments.Select(k => index.ToString() + "," + k.Name));
foreach (var dept in result)
{
Console.WriteLine(dept);
}
Result
------
0,Marketing
0,Sales
1,Advertisement
1,Production
2,Production
2,Sales
Third Overload SelectMany Operator
In this problem scenario, we need to return a new object as anonymous type which has a reference of both the employee object and department of each employee.
var result = employees.SelectMany(w => w.Departments, (employee, department) => new { employee, department });
foreach (var item in result)
{
Console.WriteLine(item.employee.Name + "," + item.department.Name);
}
Result
-------
Kapil,Marketing
Kapil,Sales
Raj,Advertisement
Raj,Production
Ramesh,Production
Ramesh,Sales
We have created an anonymous type which have a reference of employee object and department of each employee. In foreach, we print each employee name with its each department name.
SelectMany with Distinct Values
Sometimes we need to print distinct values from our child collection of target collection. Below is the sample query for the same.
var result = employees.SelectMany(w => w.Departments.Select(k => k.Name)).Distinct().ToList();
foreach (var item in result)
{
Console.WriteLine(item);
}
Result
------
Marketing
Sales
Advertisement
Production
We have a list of duplicate department names in our collection. So we have used the Distinct query operator to filter out duplicate items from the result sequence.