How it works
SelectMany turns a sequence of sequences into one sequence of elements. Flattening is useful when later work should operate on individual children rather than on groups. However, a child value may need context from its parent: a task label alone can be ambiguous if several projects contain a task with the same label.
The result-selector overload combines each outer element with each selected inner element. It lets the flattened result retain both the parent identifier and the child value. An outer element with no children contributes no flattened rows. That behavior is correct for a child-detail report, but it is different from a parent summary where empty groups may still need a visible row.
Walk through the example. The input contains a red team with two members, an empty team, and a blue team with one member. SelectMany visits the members and formats a team-name/member-name pair for each one. The result therefore has three rows, and the empty team contributes none. ToArray materializes that report once before its length and contents are displayed.
Watch the boundary. Do not assume that flattening preserves evidence of an empty parent group. If every team must appear, build a separate parent-level report or explicitly introduce an empty placeholder with a clear meaning. Also avoid re-enumerating a deferred source that performs changing or expensive work just to count the report and then print it. Materialize when a stable snapshot is required.
Practice independently. Create orders with line items and flatten them into rows containing order code, item code, and quantity. Include an empty order and two orders containing the same item code. Compare a detail report with an order-summary report and explain why their row counts differ. Add an ordinal ordering rule so the complete output is deterministic even when the input order changes.
A working example
using System;
using System.Collections.Generic;
using System.Linq;
using System.Globalization;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;
var teams = new[]
{
(Name: "red", Members: new[] { "Ada", "Sam" }),
(Name: "empty", Members: Array.Empty<string>()),
(Name: "blue", Members: new[] { "Lin" })
};
var rows = teams.SelectMany(team => team.Members, (team, member) => $"{team.Name}:{member}").ToArray();
Console.WriteLine(rows.Length);
foreach (string row in rows) Console.WriteLine(row);
Expected output
3 red:Ada red:Sam blue:Lin
Use a result selector to retain parent context, and account for empty parents separately.