C# LINQ

Query and manipulate data with ease

πŸ” What is LINQ?

LINQ (Language Integrated Query) lets you query collections using simple, readable syntax. It provides powerful methods to filter, sort, group, and transform data without writing complex loops or conditions.


// Simple LINQ query
using System.Linq;

var numbers = new[] { 1, 2, 3, 4, 5 };
var evenNumbers = numbers.Where(n => n % 2 == 0);
                                    

Core LINQ Operations

πŸ”Ž

Where

Filter items by condition

numbers.Where(n => n > 5)
πŸ”„

Select

Transform each item

names.Select(n => n.ToUpper())
πŸ“Š

OrderBy

Sort items

items.OrderBy(i => i.Price)
πŸ“¦

GroupBy

Group related items

data.GroupBy(d => d.Category)

πŸ”Ή Where - Filtering Data

The Where method filters collections based on specified conditions, returning only matching items without manual loops. It efficiently isolates elements like even numbers (2 4 6 8 10), values greater than 5 (6 7 8 9 10), or ranges between 3 and 8 (4 5 6 7). This LINQ operator streamlines data queries, enhances code readability, and improves performance by reducing iterative overhead in C# and .NET applications.

using System;
using System.Linq;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
        
        // Filter even numbers
        var evenNumbers = numbers.Where(n => n % 2 == 0);
        
        Console.WriteLine("Even numbers:");
        foreach (int num in evenNumbers)
        {
            Console.Write(num + " ");
        }
        
        // Filter numbers greater than 5
        var largeNumbers = numbers.Where(n => n > 5);
        
        Console.WriteLine("\n\nNumbers greater than 5:");
        foreach (int num in largeNumbers)
        {
            Console.Write(num + " ");
        }
        
        // Multiple conditions
        var filtered = numbers.Where(n => n > 3 && n < 8);
        
        Console.WriteLine("\n\nNumbers between 3 and 8:");
        foreach (int num in filtered)
        {
            Console.Write(num + " ");
        }
    }
}

Output:

Even numbers:

2 4 6 8 10

Numbers greater than 5:

6 7 8 9 10

Numbers between 3 and 8:

4 5 6 7

πŸ”Ή Select - Transforming Data

The Select method transforms each item in a collection into a new form, enabling flexible data manipulation. It can convert names to uppercase (ALICE, BOB, CHARLIE), calculate name lengths (5, 3, 7), or square numbers (1 4 9 16 25). This LINQ operator supports type conversions, property extraction, and custom calculations, making it ideal for data projection and preprocessing in C# programming and database operations.

using System;
using System.Linq;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        List<string> names = new List<string> { "alice", "bob", "charlie" };
        
        // Transform to uppercase
        var upperNames = names.Select(n => n.ToUpper());
        
        Console.WriteLine("Uppercase names:");
        foreach (string name in upperNames)
        {
            Console.WriteLine(name);
        }
        
        // Transform to length
        var nameLengths = names.Select(n => n.Length);
        
        Console.WriteLine("\nName lengths:");
        foreach (int length in nameLengths)
        {
            Console.WriteLine(length);
        }
        
        // Transform numbers
        List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
        var squared = numbers.Select(n => n * n);
        
        Console.WriteLine("\nSquared numbers:");
        foreach (int num in squared)
        {
            Console.Write(num + " ");
        }
    }
}

Output:

Uppercase names:

ALICE

BOB

CHARLIE

Name lengths:

5

3

7

Squared numbers:

1 4 9 16 25

πŸ”Ή OrderBy - Sorting Data

The OrderBy and OrderByDescending methods sort collections in ascending or descending order based on any property or value. They organize numbers (1 2 3 5 8 9 ascending, 9 8 5 3 2 1 descending) or alphabetize names (Alice, Bob, Charlie). These LINQ operators simplify data arrangement for displays, reports, and algorithmic processing, enhancing usability and efficiency in .NET applications.

using System;
using System.Linq;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        List<int> numbers = new List<int> { 5, 2, 8, 1, 9, 3 };
        
        // Sort ascending
        var ascending = numbers.OrderBy(n => n);
        
        Console.WriteLine("Ascending order:");
        foreach (int num in ascending)
        {
            Console.Write(num + " ");
        }
        
        // Sort descending
        var descending = numbers.OrderByDescending(n => n);
        
        Console.WriteLine("\n\nDescending order:");
        foreach (int num in descending)
        {
            Console.Write(num + " ");
        }
        
        // Sort strings
        List<string> names = new List<string> { "Charlie", "Alice", "Bob" };
        var sortedNames = names.OrderBy(n => n);
        
        Console.WriteLine("\n\nSorted names:");
        foreach (string name in sortedNames)
        {
            Console.WriteLine(name);
        }
    }
}

Output:

Ascending order:

1 2 3 5 8 9

Descending order:

9 8 5 3 2 1

Sorted names:

Alice

Bob

Charlie

πŸ”Ή First, Last, and Single

The First, Last, and Single methods retrieve specific items from collections, with strict error handling for missing elements. First gets the initial item (e.g., 10), Last retrieves the final one (e.g., 50), and Single ensures exactly one match. They throw exceptions if criteria aren’t met, providing robust data access patterns in C# LINQ queries for precise element retrieval.

using System;
using System.Linq;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        List<int> numbers = new List<int> { 10, 20, 30, 40, 50 };
        
        // Get first item
        int first = numbers.First();
        Console.WriteLine($"First: {first}");
        
        // Get last item
        int last = numbers.Last();
        Console.WriteLine($"Last: {last}");
        
        // Get first with condition
        int firstLarge = numbers.First(n => n > 25);
        Console.WriteLine($"First > 25: {firstLarge}");
        
        // FirstOrDefault (safe - returns default if not found)
        int notFound = numbers.FirstOrDefault(n => n > 100);
        Console.WriteLine($"First > 100: {notFound}");
        
        // Count items
        int count = numbers.Count();
        Console.WriteLine($"Total count: {count}");
        
        // Count with condition
        int countLarge = numbers.Count(n => n > 25);
        Console.WriteLine($"Count > 25: {countLarge}");
    }
}

Output:

First: 10

Last: 50

First > 25: 30

First > 100: 0

Total count: 5

Count > 25: 3

πŸ”Ή Any and All

The Any and All methods validate collection contents by checking conditions across elements. Any returns true if at least one item matches (e.g., True for numbers >5), while All requires every element to satisfy the condition (e.g., False if not all >5). These LINQ operators are essential for data validation, conditional logic, and efficient collection analysis in .NET development.

using System;
using System.Linq;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        List<int> numbers = new List<int> { 2, 4, 6, 8, 10 };
        
        // Check if any item matches
        bool hasLarge = numbers.Any(n => n > 5);
        Console.WriteLine($"Has number > 5: {hasLarge}");
        
        bool hasOdd = numbers.Any(n => n % 2 != 0);
        Console.WriteLine($"Has odd number: {hasOdd}");
        
        // Check if all items match
        bool allEven = numbers.All(n => n % 2 == 0);
        Console.WriteLine($"All even: {allEven}");
        
        bool allLarge = numbers.All(n => n > 5);
        Console.WriteLine($"All > 5: {allLarge}");
        
        // Check if collection has items
        bool hasItems = numbers.Any();
        Console.WriteLine($"Has items: {hasItems}");
        
        List<int> empty = new List<int>();
        bool emptyHasItems = empty.Any();
        Console.WriteLine($"Empty has items: {emptyHasItems}");
    }
}

Output:

Has number > 5: True

Has odd number: False

All even: True

All > 5: False

Has items: True

Empty has items: False

πŸ”Ή Sum, Average, Min, Max

The aggregate methods Sum, Average, Min, and Max perform statistical calculations on collections for data analysis. They compute totals (438), averages (87.6), minimums (78), and maximums (95), with support for conditional filtering (e.g., average of scores >85: 91.67). These LINQ functions are invaluable for analytics, reporting, and operational insights in C# applications.

using System;
using System.Linq;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        List<int> scores = new List<int> { 85, 92, 78, 95, 88 };
        
        // Calculate sum
        int total = scores.Sum();
        Console.WriteLine($"Total: {total}");
        
        // Calculate average
        double average = scores.Average();
        Console.WriteLine($"Average: {average}");
        
        // Find minimum
        int min = scores.Min();
        Console.WriteLine($"Minimum: {min}");
        
        // Find maximum
        int max = scores.Max();
        Console.WriteLine($"Maximum: {max}");
        
        // Count items
        int count = scores.Count();
        Console.WriteLine($"Count: {count}");
        
        // Combine operations
        var highScores = scores.Where(s => s > 85);
        double highAverage = highScores.Average();
        Console.WriteLine($"Average of scores > 85: {highAverage}");
    }
}

Output:

Total: 438

Average: 87.6

Minimum: 78

Maximum: 95

Count: 5

Average of scores > 85: 91.66666666666667

🧠 Test Your Knowledge

Which LINQ method filters items based on a condition?