Lesson 21 — Language Integrated Query

LINQ

LINQ is one of C#'s most powerful features — composable, readable queries over collections, databases, and any IEnumerable source without writing loops.

CSHARP — LINQ method syntax
using System.Linq;

int[] marks = { 45, 72, 80, 58, 91, 66, 55, 38 };

// Filtering:
var passing = marks.Where(m => m >= 50).ToList();
Console.WriteLine($"Passing: {string.Join(", ", passing)}");

// Projection (transform each element):
var labels = marks.Select(m => m >= 50 ? "Pass" : "Fail").ToList();

// Aggregation:
Console.WriteLine($"Average: {marks.Average():F1}");
Console.WriteLine($"Max:     {marks.Max()}");
Console.WriteLine($"Count >= 70: {marks.Count(m => m >= 70)}");

// Sorting:
var top3 = marks.OrderByDescending(m => m).Take(3).ToList();
Console.WriteLine($"Top 3: {string.Join(", ", top3)}");

LINQ on Objects

CSHARP — LINQ on objects
var learners = new List<Learner> { /* ... */ };

// Chain operations:
var results = learners
    .Where(l => l.Mark >= 50)              // filter
    .OrderByDescending(l => l.Mark)        // sort
    .ThenBy(l => l.Name)                   // secondary sort
    .Select(l => new {                     // project to anonymous type
        l.Name,
        l.Course,
        Grade = l.Mark >= 80 ? "Distinction"
              : l.Mark >= 60 ? "Merit" : "Pass"
    })
    .ToList();

foreach (var r in results)
    Console.WriteLine($"{r.Name,-15} {r.Course,-10} {r.Grade}");

// Grouping:
var byCourse = learners
    .GroupBy(l => l.Course)
    .Select(g => new { Course = g.Key, Count = g.Count(), Avg = g.Average(l => l.Mark) });

foreach (var g in byCourse)
    Console.WriteLine($"{g.Course}: {g.Count} learners, avg {g.Avg:F1}%");

Practice Task

Your Turn

Given a List of learners with Name, Course, Mark: (1) find all with mark >= 60 sorted by mark descending, (2) calculate average per course using GroupBy, (3) find the top learner overall, (4) create a Dictionary mapping name to grade label using ToDictionary. Print all results.

Common Mistakes

  • Forgetting using System.Linq;
  • Multiple enumeration without ToList() — lazy evaluation means the query runs every time you enumerate.
  • LINQ in a loop that calls the database — use ToList() to materialise first.
  • Overly complex LINQ chains — sometimes a foreach loop is clearer.

Professional Tip

LINQ is lazy — the query is not executed until you enumerate it (foreach, ToList, Count, etc.). This is powerful but means calling ToList() at the right moment matters for performance.

Mini Quiz

What does .Where(m => m >= 50) do in LINQ?