Skip to content

C# LINQ SelectMany — Complete Guide

DodaTech Updated 2026-06-24 2 min read

In this tutorial, you'll learn about C# LINQ SelectMany. We cover key concepts, practical examples, and best practices.

You have a list of orders, each containing multiple items. You need a flat list of all items across all orders. You write nested foreach loops. The LINQ SelectMany method projects each element to a sequence and flattens the result into a single sequence.

Wrong

var allItems = new List<OrderItem>();
foreach (var order in orders)
{
    foreach (var item in order.Items)
    {
        allItems.Add(item);
    }
}

Output: Works. Six lines of nested loops for a simple flatten operation.

var allItems = orders.SelectMany(order => order.Items).ToList();

Output: Same list, one line. SelectMany takes each order, extracts order.Items, and flattens all item lists into one.

SelectMany also provides the parent index:

var indexed = orders.SelectMany((order, orderIndex) =>
    order.Items.Select(item => $"{orderIndex}: {item.Name}"));

For query syntax:

var allItems = from order in orders
               from item in order.Items
               select item;

Prevention

  • Use SelectMany for nested foreach flattening.
  • Use SelectMany when each input element produces zero or more output elements.
  • Use SelectMany with IQueryable for server-side flattening (cross-join or SelectMany in SQL).
  • Use SelectMany with an optional result selector: .SelectMany(x => x.Items, (x, item) => new { x.Id, item.Name }).
  • Use Select when each input produces exactly one output element.
  • Use Where followed by Select if you need filtering before flattening.

Common Mistakes with linq select many

  1. Using head and tail instead of pattern matching, causing runtime errors on empty lists
  2. Forgetting that lazy evaluation defers computation until the value is forced, causing space leaks with unevaluated thunks
  3. Using return to exit a function early instead of wrapping a pure value in the monad

These mistakes appear frequently in real-world CSHARP code. DodaTech's contributors have identified these patterns through analysis of open-source projects and production systems.

Practice Exercise

Write a pure function that safely divides two integers using Maybe, then test it with edge cases like division by zero and negative numbers.

This exercise reinforces the concepts covered in this guide. Try implementing it before checking online solutions.

FAQ

What is the difference between Select and SelectMany?

Select produces one output per input: IEnumerable<T> → IEnumerable<U>. SelectMany produces zero or more outputs per input and flattens: IEnumerable<T> → IEnumerable<IEnumerable<U>> → IEnumerable<U>. Use Select for 1:1 mapping, SelectMany for 1:n mapping.

Can SelectMany be used with IQueryable for cross joins?

Yes. db.Orders.SelectMany(order => db.OrderItems) translates to SELECT ... FROM Orders CROSS JOIN OrderItems or the equivalent SELECT ... FROM Orders, OrderItems. This is a cross join — every order paired with every item. Add a Where for an inner join.

How do I filter the inner sequence in SelectMany?

Use another LINQ method inside the selector: orders.SelectMany(order => order.Items.Where(item => item.Price > 10)). The Where runs on each inner sequence before flattening.

SelectMany is used in DodaTech's reporting to flatten hierarchical data. For more LINQ, visit DodaTech.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro