C# LINQ
LINQ (Language Integrated Query) lets you query, filter, sort, and transform data using a readable, SQL-like syntax directly in C#. It works on arrays, lists, XML, databases, and any collection that implements IEnumerable.
Why LINQ?
┌──────────────────────────────────────────────────────────────┐ │ WITHOUT LINQ — manual loop logic: │ │ │ │ List<int> result = new List<int>(); │ │ foreach (int n in numbers) │ │ if (n > 10) │ │ result.Add(n); │ │ result.Sort(); │ │ │ │ WITH LINQ — declarative one-liner: │ │ │ │ var result = numbers.Where(n => n > 10).OrderBy(n => n); │ └──────────────────────────────────────────────────────────────┘
Two LINQ Syntax Styles
LINQ offers two equivalent styles — Method Syntax (fluent) and Query Syntax (SQL-like). Both produce identical results.
int[] numbers = { 5, 12, 3, 20, 8, 17, 1 };
// Method syntax (most common in practice):
var result1 = numbers.Where(n => n > 10).OrderBy(n => n);
// Query syntax (SQL-like):
var result2 = from n in numbers
where n > 10
orderby n
select n;
// Both give: { 12, 17, 20 }
Core LINQ Methods
Where — Filter
List<string> names = new List<string>() { "Alice", "Bob", "Carol", "Dave", "Eve" };
var shortNames = names.Where(n => n.Length <= 3);
// [Bob, Eve]
var startsWithC = names.Where(n => n.StartsWith("C"));
// [Carol]
Select — Transform
int[] scores = { 80, 90, 70, 95 };
var doubled = scores.Select(s => s * 2);
// [160, 180, 140, 190]
var graded = scores.Select(s => s >= 90 ? "A" : s >= 80 ? "B" : "C");
// ["B", "A", "C", "A"]
OrderBy and OrderByDescending
var sorted = scores.OrderBy(s => s); // ascending
var sortedDesc = scores.OrderByDescending(s => s); // descending
List<string> words = new List<string>() { "Banana", "Apple", "Cherry" };
var alpha = words.OrderBy(w => w); // [Apple, Banana, Cherry]
var byLen = words.OrderBy(w => w.Length); // [Apple, Banana, Cherry]
First, Last, Single
int[] data = { 3, 7, 2, 9, 4 };
Console.WriteLine(data.First()); // 3
Console.WriteLine(data.Last()); // 4
Console.WriteLine(data.First(n => n > 5)); // 7
Console.WriteLine(data.FirstOrDefault(n => n > 100)); // 0 (default — no match)
Count, Sum, Average, Min, Max
int[] values = { 10, 20, 30, 40, 50 };
Console.WriteLine(values.Count()); // 5
Console.WriteLine(values.Sum()); // 150
Console.WriteLine(values.Average()); // 30
Console.WriteLine(values.Min()); // 10
Console.WriteLine(values.Max()); // 50
// With condition:
Console.WriteLine(values.Count(v => v > 25)); // 3
Console.WriteLine(values.Sum(v => v * 2)); // 300
Any and All
int[] nums = { 2, 4, 6, 7, 8 };
Console.WriteLine(nums.Any(n => n % 2 != 0)); // True — at least one odd
Console.WriteLine(nums.All(n => n % 2 == 0)); // False — not all even (7 is odd)
Console.WriteLine(nums.Any()); // True — list is not empty
Skip and Take
int[] pages = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
var page2 = pages.Skip(3).Take(3); // skip first 3, take next 3
// [4, 5, 6]
// Pagination example:
int pageSize = 5;
int pageNumber = 2; // 1-based
var pageData = pages.Skip((pageNumber - 1) * pageSize).Take(pageSize);
// [6, 7, 8, 9, 10]
Distinct and GroupBy
int[] withDups = { 1, 2, 2, 3, 3, 3, 4 };
var unique = withDups.Distinct();
// [1, 2, 3, 4]
// GroupBy:
string[] words = { "cat", "car", "bat", "bar", "ant" };
var groups = words.GroupBy(w => w[0]); // group by first letter
foreach (var group in groups)
{
Console.WriteLine($"Letter '{group.Key}': " + string.Join(", ", group));
}
// Letter 'c': cat, car
// Letter 'b': bat, bar
// Letter 'a': ant
LINQ on Objects
class Product
{
public string Name;
public string Category;
public double Price;
}
List<Product> products = new List<Product>()
{
new Product { Name="Laptop", Category="Electronics", Price=999 },
new Product { Name="Phone", Category="Electronics", Price=499 },
new Product { Name="Desk", Category="Furniture", Price=250 },
new Product { Name="Chair", Category="Furniture", Price=150 },
new Product { Name="Monitor", Category="Electronics", Price=350 },
};
// Get all electronics sorted by price:
var electronics = products
.Where(p => p.Category == "Electronics")
.OrderBy(p => p.Price)
.Select(p => $"{p.Name}: ${p.Price}");
foreach (var item in electronics) Console.WriteLine(item);
// Monitor: $350
// Phone: $499
// Laptop: $999
// Average price by category:
var avgByCategory = products
.GroupBy(p => p.Category)
.Select(g => new { Category = g.Key, Avg = g.Average(p => p.Price) });
foreach (var item in avgByCategory)
Console.WriteLine($"{item.Category}: avg ${item.Avg}");
// Electronics: avg $616
// Furniture: avg $200
LINQ Data Pipeline Diagram
┌──────────────────────────────────────────────────────────────┐ │ Source Data │ │ [Laptop $999] [Phone $499] [Desk $250] [Chair $150] │ │ │ │ │ ▼ .Where(p => p.Price > 200) │ │ [Laptop $999] [Phone $499] [Desk $250] │ │ │ │ │ ▼ .OrderBy(p => p.Price) │ │ [Desk $250] [Phone $499] [Laptop $999] │ │ │ │ │ ▼ .Select(p => p.Name) │ │ ["Desk", "Phone", "Laptop"] │ └──────────────────────────────────────────────────────────────┘
Query Syntax vs Method Syntax
// Query syntax:
var result = from p in products
where p.Price > 300
orderby p.Name
select p.Name;
// Method syntax equivalent:
var result = products
.Where(p => p.Price > 300)
.OrderBy(p => p.Name)
.Select(p => p.Name);
Quick Reference
┌─────────────────────────┬─────────────────────────────────────┐ │ Method │ Purpose │ ├─────────────────────────┼─────────────────────────────────────┤ │ Where(condition) │ Filter matching items │ │ Select(transform) │ Project / transform each item │ │ OrderBy / OrderByDesc │ Sort ascending / descending │ │ First / Last │ Get first or last item │ │ FirstOrDefault │ First match or default value │ │ Count / Sum / Avg │ Aggregate calculations │ │ Min / Max │ Smallest or largest value │ │ Any / All │ Check any/all match condition │ │ Skip / Take │ Pagination │ │ Distinct │ Remove duplicates │ │ GroupBy │ Group items by key │ │ ToList / ToArray │ Execute query into collection │ └─────────────────────────┴─────────────────────────────────────┘
LINQ transforms how you think about data processing in C#. Instead of writing loops and conditionals manually, you describe what you want — and LINQ figures out how to get it. It is one of the most productive features in the language and is used in virtually every real-world C# application.
