C# guide

LINQ Samples

Learn LINQ with short C# examples, exact output, and side-by-side explanations of query syntax, method syntax, deferred execution, filtering, projection, grouping, joins and aggregation.

Where Select GroupBy Join OrderBy Any / All Sum / Average ToList

What is LINQ?

LINQ, or Language Integrated Query, is a C# feature that lets you query collections using readable, composable expressions. You can use it to filter lists, transform objects, sort results, group records, join collections and calculate totals.

This page focuses on LINQ to Objects, which means the examples run against in-memory C# collections such as List<T> and arrays.

Source

A collection such as customers, products or orders.

Query

A chain of operations such as Where, Select and OrderBy.

Execution

The moment the query is actually evaluated, often during enumeration.

How LINQ executes

Many LINQ operators use deferred execution. That means the query is created first, but the actual work happens later, usually when you loop through it or materialise it with ToList(), ToArray() or similar methods.

A LINQ query is like a recipe. It describes what should happen, but it does not always cook the meal immediately.

Deferred execution example

Execution
var products = new List<string> { "Keyboard", "Mouse" };

var query = products.Where(p => p.StartsWith("M"));

products.Add("Monitor");

var result = query.ToList();
Output: ["Mouse", "Monitor"]

Shared sample data

All examples below reuse the same small dataset. This makes it easier to compare operators without learning a new business scenario each time.

C# records and collections

Dataset
public record Customer(int Id, string Name, string City, bool IsVip);
public record Supplier(int Id, string Name, string Country);
public record Product(int Id, string Name, string Category, decimal Price, int SupplierId);
public record Order(int Id, int CustomerId, decimal Total);

var customers = new List<Customer>
{
    new(1, "Ada", "London", true),
    new(2, "Ben", "Bristol", false),
    new(3, "Cara", "London", true),
    new(4, "Dan", "Leeds", false)
};

var suppliers = new List<Supplier>
{
    new(1, "Northwind Input", "UK"),
    new(2, "Pixel Displays", "DE"),
    new(3, "Office Glow", "UK")
};

var products = new List<Product>
{
    new(1, "Keyboard", "Hardware", 50m, 1),
    new(2, "Mouse", "Hardware", 25m, 1),
    new(3, "Monitor", "Display", 200m, 2),
    new(4, "Desk Lamp", "Office", 30m, 3),
    new(5, "Laptop Stand", "Office", 45m, 3)
};

var orders = new List<Order>
{
    new(1001, 1, 75m),
    new(1002, 2, 200m),
    new(1003, 1, 75m)
};

Query syntax vs method syntax

LINQ can be written in query syntax or method syntax. Query syntax looks closer to SQL, while method syntax is fluent and works with every standard LINQ operator.

Query syntax

SQL-like
var names =
    from c in customers
    where c.City == "London"
    select c.Name;
Output: ["Ada", "Cara"]

Method syntax

Fluent
var names = customers
    .Where(c => c.City == "London")
    .Select(c => c.Name);
Output: ["Ada", "Cara"]

LINQ operator samples

The examples below cover the most useful LINQ operators for day-to-day C# development.

Category Operators Use case
Filtering Where Keep only items matching a condition.
Projection Select, SelectMany Transform objects into a new shape.
Ordering OrderBy, ThenBy Sort results by one or more fields.
Grouping GroupBy Group items by a shared key.
Joins Join, GroupJoin Combine related collections.
Aggregation Count, Sum, Average Calculate totals, counts and averages.

Filtering with Where

Filtering
var affordableOfficeProducts = products
    .Where(p => p.Category == "Office" && p.Price < 50m)
    .Select(p => p.Name)
    .ToList();
Output: ["Desk Lamp", "Laptop Stand"]

Projection with Select

Projection
var productLabels = products
    .Select(p => $"{p.Name}: £{p.Price}")
    .ToList();
Output: ["Keyboard: £50", "Mouse: £25", "Monitor: £200", "Desk Lamp: £30", "Laptop Stand: £45"]

Ordering with OrderBy and ThenBy

Ordering
var orderedProducts = products
    .OrderBy(p => p.Category)
    .ThenByDescending(p => p.Price)
    .Select(p => $"{p.Category}: {p.Name}")
    .ToList();
Output: ["Display: Monitor", "Hardware: Keyboard", "Hardware: Mouse", "Office: Laptop Stand", "Office: Desk Lamp"]

Grouping with GroupBy

Grouping
var categoryCounts = products
    .GroupBy(p => p.Category)
    .Select(g => $"{g.Key}: {g.Count()}")
    .OrderBy(x => x)
    .ToList();
Output: ["Display: 1", "Hardware: 2", "Office: 2"]

Inner join with Join

Join
var supplierProducts = products
    .Join(
        suppliers,
        product => product.SupplierId,
        supplier => supplier.Id,
        (product, supplier) => $"{product.Name}: {supplier.Name}"
    )
    .ToList();
Output: ["Keyboard: Northwind Input", "Mouse: Northwind Input", "Monitor: Pixel Displays", "Desk Lamp: Office Glow", "Laptop Stand: Office Glow"]

Aggregation with Sum and Average

Aggregation
var orderSummary = new
{
    Count = orders.Count(),
    Revenue = orders.Sum(o => o.Total),
    Average = Math.Round(orders.Average(o => o.Total), 2)
};
Output: Count: 3 Revenue: 350 Average: 116.67

Quantifiers with Any and All

Boolean
var checks = new
{
    HasVip = customers.Any(c => c.IsVip),
    AllHaveCity = customers.All(c => !string.IsNullOrWhiteSpace(c.City)),
    HasLargeOrder = orders.Any(o => o.Total > 150m)
};
Output: HasVip: true AllHaveCity: true HasLargeOrder: true

Partitioning with Take and Skip

Paging
var pageSize = 2;
var pageTwo = products
    .OrderBy(p => p.Id)
    .Skip(pageSize)
    .Take(pageSize)
    .Select(p => p.Name)
    .ToList();
Output: ["Monitor", "Desk Lamp"]

Performance and common mistakes

LINQ is expressive, but a few details matter. Deferred execution can rerun work. Sorting and grouping may buffer the source. Materialising with ToList() gives you a snapshot, but it also uses memory immediately.

Pitfall Why it matters Safer approach
Using Single too casually It throws if there are zero or multiple matches. Use FirstOrDefault when duplicates are not a bug.
Calling OrderBy twice The second OrderBy replaces the first ordering. Use ThenBy for secondary sorting.
Adding ToList() everywhere It forces immediate execution and allocates memory. Materialise only when you need a snapshot.
Assuming Distinct sorts data It removes duplicates, but it is not a presentation sort. Add OrderBy when order matters.

Test the examples

A good LINQ sample should be easy to test. Keep queries pure, return concrete results and assert the output.

xUnit-style assertions

Testing
Assert.Equal(
    new[] { "Ada", "Cara" },
    customers
        .Where(c => c.City == "London")
        .Select(c => c.Name)
        .ToList()
);

Assert.Equal(350m, orders.Sum(o => o.Total));

Assert.Throws<InvalidOperationException>(
    () => customers.Single(c => c.City == "London")
);