Skip to content
Search lessons, topics, tests…
Esc

    ↑ ↓ moveEnter openEsc close
    Cheat sheets: all cheat sheets

    Select vs SelectMany in LINQ to Objects: Projection or Flattening

    Learn how to choose between Select and SelectMany in LINQ to Objects by recognizing when you want one output per input versus flattening nested sequences into a single stream.

    Learning outcome

    By the end of this note, you should be able to choose Select when you want a one-to-one projection and SelectMany when each source element produces zero, one, or many results that should be flattened into a single sequence. In interviews, the key signal is not “which one looks shorter,” but “what shape should the final sequence have?”

    Intuition

    Think of Select as a mapper: for every item in the source, it creates exactly one result element in the output sequence. The output therefore keeps the same outer shape as the input.

    For example, use Select to project each word to its length. The result is still a sequence of the same count as the input.

    By contrast, SelectMany is for nested results. If each outer item contains an inner sequence, and you want one flat sequence containing all inner items, use SelectMany.

    For example, flatten the tag collections with SelectMany; each post can contribute multiple tags, and the result is one flattened sequence of tags.

    Deep dive

    In LINQ to Objects, both operators are deferred: they build an iterator pipeline and only run when you enumerate the result. The difference is the shape of the iteration.

    • Select: one source element -> one projected element
    • SelectMany: one source element -> many inner elements, flattened into one output stream

    A common interview framing is:

    • Use Select when you want to transform each item into another item.
    • Use SelectMany when you want to transform each item into a collection and then concatenate all those collections.

    A practical distinction is nesting depth. If your projection returns a scalar or a single object, Select is appropriate. If your projection returns IEnumerable<T> and you want to remove one layer of nesting, SelectMany is usually the right operator.

    Projecting each customer to their Orders collection with Select produces a sequence of sequences. Flattening those collections with SelectMany produces a single sequence of orders.

    Another useful rule: SelectMany can also carry context from the outer element into the flattened result by using its result selector overload. That is helpful when you need both the parent and child values.

    The key interview insight is that SelectMany is not “advanced Select.” It solves a different shape problem.

    Failure modes

    Using Select to return collections is valid when you want nesting. It is a mistake only when the desired result is flat: then each output element is still a collection instead of one child item.

    Another mistake is using SelectMany when you only need one output per input. That can hide a simpler intent and make debugging harder.

    Be careful not to confuse LINQ to Objects with database translation. In-memory LINQ executes actual delegates over objects. In database-backed LINQ providers, query translation may rewrite expressions into SQL, but this note is about object sequences only.

    Choose the intended result shape before materializing it. Neither operator promises a List<T>; if a caller specifically needs a list, materialize the chosen projection afterward.

    Interview drill — worked answers

    1. Students each have a course list. How do you get all courses? Choose SelectMany. If Maya has [C#, SQL] and Ravi has [SQL], flattening gives [C#, SQL, SQL]. It does not remove duplicates. By contrast, projecting each course list with Select keeps two outer elements, each a list.
    2. Products need to become a list of prices. Which operator fits? Choose Select for the price projection, then materialize if a List<decimal> is required. Three products produce three price entries, even if two products share a price.
    3. How do you keep student names with every course? Use the result-selector form of SelectMany: choose each student's courses, then combine the current student and course into one result. Maya's two courses produce two labeled rows; Ravi's one course produces one.
    4. Is SelectMany only for joins? No. The department example below has no join condition: it simply visits the existing employee collections. The operator also supports query patterns that combine sequences, but flattening is the underlying operation.
    5. Why is Support visible in one report and absent from the others? The count projection emits one row for each department, including Support -> 0. Both flattened reports emit one row per employee, so Support's empty employee collection contributes zero rows.

    Revision checklist

    • I can explain Select as one-to-one projection.
    • I can explain SelectMany as flattening nested sequences.
    • I can predict whether the result is nested or flat.
    • I can choose the operator based on desired output shape, not syntax familiarity.
    • I can distinguish LINQ to Objects behavior from query provider translation.

    Production code

    The example below shows both operators side by side over in-memory objects. Here Select produces one count summary per department, while SelectMany produces one row per employee. A different projection returning the employee collection itself would preserve nesting.

    Executable code examples

    Select vs SelectMany over nested in-memory data

    Program.cs

    C#Runs
    using System;
    using System.Collections.Generic;
    using System.Linq;
    
    var departments = new List<Department>
    {
        new("Engineering", new List<string> { "Ada", "Grace" }),
        new("Design", new List<string> { "Edsger" }),
        new("Support", Array.Empty<string>())
    };
    
    var employeeCounts = departments.Select(d => new { d.Name, Count = d.Employees.Count });
    var allEmployees = departments.SelectMany(d => d.Employees);
    var labeledEmployees = departments.SelectMany(
        d => d.Employees,
        (department, employee) => $"{department.Name}:{employee}");
    
    Console.WriteLine("Select keeps one result per department:");
    foreach (var item in employeeCounts)
    {
        Console.WriteLine($"{item.Name} -> {item.Count}");
    }
    
    Console.WriteLine();
    Console.WriteLine("SelectMany flattens all employees:");
    foreach (var employee in allEmployees)
    {
        Console.WriteLine(employee);
    }
    
    Console.WriteLine();
    Console.WriteLine("SelectMany can keep parent context too:");
    foreach (var item in labeledEmployees)
    {
        Console.WriteLine(item);
    }
    
    public sealed record Department(string Name, IReadOnlyList<string> Employees);

    Code walkthrough

    The employeeCounts query uses Select because each department becomes exactly one anonymous result with a name and a count. Even though the count is derived from a collection, the output is still one item per department.

    The allEmployees query uses SelectMany because each department contributes zero or more employees, and the final goal is a single flat stream of employee names. The empty support department contributes nothing, which is a normal and useful result of flattening.

    The labeledEmployees query demonstrates the result-selector overload of SelectMany. It is especially useful when you want to flatten child data while still retaining information from the parent object.

    Trace the rows: Engineering contributes Ada then Grace; Design contributes Edsger; Support contributes none. The labeled query follows the same three employees and prefixes each with its department. The three count summaries and three employee rows happen to have the same count in this dataset; that coincidence does not make their shapes or meanings identical.

    A good interview summary is:

    • Select produces one result per source element; the result type may stay the same or change.
    • SelectMany flattens one layer of selected child sequences; its result selector can also change the element type.

    If you remember that distinction, you will usually choose correctly under pressure.

    Output: Select vs SelectMany over nested in-memory data

    Select keeps one result per department:
    Engineering -> 2
    Design -> 1
    Support -> 0

    SelectMany flattens all employees:
    Ada
    Grace
    Edsger

    SelectMany can keep parent context too:
    Engineering:Ada
    Engineering:Grace
    Design:Edsger

    TechInterviewNotes Editorial Team · Updated 7 Oct 2026 ·