[LINQ Operators] SelectMany

The “SelectMany” operator performs a one-to-many element projection over a sequence. You might think the operator is not intuitive like others. Unlike the “Select” operator, the “SelectMany” operator yields a collection per each object by the selector function. The final result will be a single collection flattened from all intermediate collections.

 

1. Sample Data Object

To test examples, you need to include the <data classes> in your project.

 

2. “SelectMany” operator

  • Deferred operator
  • Purpose: Projection

 

3. Prototypes

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)

public static IEnumerable<TResult> SelectMany<TSource, TCollection, TResult>(
  this IEnumerable<TSource> source,
  Func<TSource, int, IEnumerable<TCollection>> collectionSelector,
  Func<TSource, TCollection, TResult> resultSelector)

The first 2 signatures of the “SelectMay()” operator are similar with that of “Select()” except the last parameter of Func<>.

The type of the last parameter is

  • Select” operator:  TResult
  • SelectMany” operator : IEnumerable<TResult>

The result is a little bit complicated. For each input object, it creates a collection specified by a selector Func. At the end of the iteration, you will get multiple collections. The final result is a single collection flattened from these intermediate collections.

SelectMany()” is usually used to retrieve data from one-to-many relationships.

The second prototype has an integer input argument; which is an index number (zero-based) for the element from the input sequence.

The power of the “SelectMany()” operator is from the last 2 signatures.  They have 2 selectors; the first selector is passed to the next one and creates a result. It’s hard to understand what’s going on just by looking at signatures. Please look at the examples.

 

4. Example 1 (Standard Operator): one selector

// The results will be IEnumerable<Employee>
IEnumerable<DepartmentEmployees> depEmps
  = DepartmentEmployees.GetDepartmentEmployees();
// select employees of each department
IEnumerable<Employee> emps
  = depEmps.SelectMany(de => de.Employees);

foreach (Employee e in emps)
{
  Console.WriteLine("${e.Name}");
}

In this example, each department object is linked to an “Employee” collection. If you use the “Select()” operator, the result will be “IEnumerable<List<Employee>>” rather than “IEnumerable<Employee>”.

 

5. Example 2 (Standard Operator): two selectors

// Requires 2 delegates
IEnumerable<DepartmentEmployees> depEmps
  = DepartmentEmployees.GetDepartmentEmployees();

// first delegate's "de.Employees" becomes "deEmps" of the second one
var newDepEmps
  = depEmps.SelectMany(de => de.Employees,
    (de, deEmps) => new
  {
    Department = de.Department.Name, Employee = deEmps.Name
  });

foreach (var de in newDepEmps)
{
  Console.WriteLine($"{de.Department}: {de.Employee}");
}

In this example, you can create the second selector function using the selected object and its intermediate collection.

 

6. Example 3 (Query Expression):

There is no direct translation to a query expression.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s