C#
03 / 07

LINQ & Collections

C#: LINQ & Collections

LINQ (Language Integrated Query) provides a unified syntax for querying arrays, lists, XML, databases, and any IEnumerable<T> source. It uses deferred execution — queries run when iterated, not when defined.

LINQ Query Syntax

var users = new List<User> { /* ... */ };

// Query syntax (SQL-like)
var result = from u in users
             where u.Age >= 18
             orderby u.Name
             select new { u.Id, u.Name };

// Method syntax (more composable — prefer for most cases)
var result2 = users
    .Where(u => u.Age >= 18)
    .OrderBy(u => u.Name)
    .Select(u => new { u.Id, u.Name });

// Common LINQ operators
users.Where(u => u.IsActive)            // filter
users.Select(u => u.Name)              // project
users.SelectMany(u => u.Orders)        // flatten nested collections
users.OrderBy(u => u.Name)             // sort ascending
users.OrderByDescending(u => u.Age)    // sort descending
users.GroupBy(u => u.Department)       // group
users.Join(orders,                     // inner join
    u => u.Id,
    o => o.UserId,
    (u, o) => new { u.Name, o.Total })
users.Distinct()                       // remove duplicates
users.Take(10)                         // first N
users.Skip(20).Take(10)               // pagination
users.FirstOrDefault(u => u.Id == 5)  // first match or null
users.SingleOrDefault(u => u.Id == 5) // exactly one match or null
users.Any(u => u.IsAdmin)             // exists
users.All(u => u.IsActive)            // all match
users.Count(u => u.IsActive)         // count matching
users.Sum(u => u.Orders.Count)        // aggregate
users.Min(u => u.Age)
users.Max(u => u.Age)
users.Average(u => u.Score)
users.ToList()                         // materialize — execute query

Grouping & Joins

// GroupBy
var byDepartment = users
    .GroupBy(u => u.Department)
    .Select(g => new {
        Department = g.Key,
        Count = g.Count(),
        AvgAge = g.Average(u => u.Age),
        Names = g.Select(u => u.Name).ToList()
    });

// Left join with GroupJoin
var usersWithOrders = users
    .GroupJoin(orders,
        u => u.Id,
        o => o.UserId,
        (user, userOrders) => new {
            User = user,
            Orders = userOrders.ToList(),
            OrderCount = userOrders.Count()
        });

// Zip — combine two sequences element-by-element
var names = new[] { "Alice", "Bob" };
var scores = new[] { 95, 82 };
var combined = names.Zip(scores, (name, score) => $"{name}: {score}");

// Deferred execution — query is not executed here
var query = users.Where(u => u.IsActive);  // IEnumerable<User> — not yet run
// Executed here:
foreach (var u in query) { }  // or: query.ToList(), query.Count(), etc.

Collections

// List<T> — resizable array
var list = new List<string> { "a", "b", "c" };
list.Add("d");
list.Insert(0, "z");
list.Remove("b");
list.RemoveAt(0);
list.Sort();
list.BinarySearch("c");  // fast search on sorted list

// Dictionary<TKey, TValue>
var dict = new Dictionary<string, int>
{
    ["one"] = 1,
    ["two"] = 2,
};
dict["three"] = 3;
dict.TryGetValue("one", out int val);  // safe get
dict.ContainsKey("four");              // check existence
foreach (var (key, value) in dict) { }  // deconstruct KeyValuePair

// HashSet<T> — unique values, O(1) lookup
var set = new HashSet<int> { 1, 2, 3 };
set.Add(4);
set.Contains(2);  // O(1)
set.UnionWith(new[] { 3, 4, 5 });      // union
set.IntersectWith(new[] { 2, 3 });     // intersection
set.ExceptWith(new[] { 1 });           // difference

// Queue<T> and Stack<T>
var queue = new Queue<string>();
queue.Enqueue("first");
var next = queue.Dequeue();  // FIFO

var stack = new Stack<int>();
stack.Push(1);
var top = stack.Pop();  // LIFO

// ImmutableList, ImmutableDictionary (System.Collections.Immutable)
var immutable = ImmutableList.Create(1, 2, 3);
var added = immutable.Add(4);  // returns new list, original unchanged

// Span<T> — stack-allocated slice (no heap allocation)
Span<int> slice = numbers.AsSpan(2, 3);  // elements 2, 3, 4

Keep your own version of these notes — editable, searchable, and organised by your stack.

Start free