The .NET collections framework provides generic, type-safe containers. LINQ (Language Integrated Query) adds declarative querying over any IEnumerable<T>.

Lists and Arrays

  var numbers = new List<int> { 1, 2, 3, 4, 5 };
numbers.Add(6);

int[] arr = { 10, 20, 30 };
Console.WriteLine($"Count: {numbers.Count}, first: {arr[0]}");

foreach (var n in numbers)
    Console.Write($"{n} ");
Console.WriteLine();
  

Dictionary

  var scores = new Dictionary<string, int>
{
    ["Alice"] = 95,
    ["Bob"] = 87,
};

scores["Charlie"] = 92;

if (scores.TryGetValue("Alice", out int score))
    Console.WriteLine($"Alice: {score}");
  

HashSet

  var unique = new HashSet<string> { "a", "b", "c" };
unique.Add("a");  // ignored

var other = new HashSet<string> { "b", "c", "d" };
unique.IntersectWith(other);
Console.WriteLine(string.Join(", ", unique));  // b, c
  

LINQ Query Syntax

  var products = new[]
{
    new { Name = "Laptop", Price = 999.99 },
    new { Name = "Mouse", Price = 29.99 },
    new { Name = "Keyboard", Price = 79.99 },
};

var expensive = from p in products
                where p.Price > 50
                orderby p.Price descending
                select p.Name;

foreach (var name in expensive)
    Console.WriteLine(name);
  

LINQ Method Syntax

  var numbers = Enumerable.Range(1, 10);

var evens = numbers
    .Where(n => n % 2 == 0)
    .Select(n => n * n)
    .ToList();

Console.WriteLine(string.Join(", ", evens));  // 4, 16, 36, 64, 100

int sum = numbers.Sum();
double avg = numbers.Average();
int max = numbers.Max();
  

Common LINQ Methods

Method Purpose
Where Filter elements
Select Transform elements
OrderBy Sort ascending
GroupBy Group by key
FirstOrDefault First match or default
Any / All Predicate checks

LINQ queries are deferred — they execute when you iterate or call a terminal method like ToList().

Queue, Stack, and LinkedList

  var queue = new Queue<string>();
queue.Enqueue("first");
queue.Enqueue("second");
Console.WriteLine(queue.Dequeue());  // first

var stack = new Stack<int>();
stack.Push(1);
stack.Push(2);
Console.WriteLine(stack.Pop());  // 2
  

Immutable Collections

  using System.Collections.Immutable;

var builder = ImmutableList.CreateBuilder<int>();
builder.Add(1);
builder.Add(2);
var immutable = builder.ToImmutable();
// immutable.Add(3) — does not exist; returns new list
var updated = immutable.Add(3);
  

Use immutable collections when sharing data across threads.

Advanced LINQ

  var sales = new[]
{
    new { Region = "East", Amount = 100 },
    new { Region = "West", Amount = 200 },
    new { Region = "East", Amount = 150 },
};

var byRegion = sales
    .GroupBy(s => s.Region)
    .Select(g => new { Region = g.Key, Total = g.Sum(s => s.Amount) });

var top = sales.OrderByDescending(s => s.Amount).First();
var hasLarge = sales.Any(s => s.Amount > 500);
  

IEnumerable vs List

Type Materialized Use when
IEnumerable<T> No (deferred) Passing query pipelines
List<T> Yes Random access, mutation
IReadOnlyList<T> Yes Return without allowing mutation

Call .ToList() only when you need multiple enumeration or indexing.

Performance Tips

  • Use HashSet<T> for O(1) lookups instead of List.Contains().
  • Prefer Dictionary.TryGetValue over ContainsKey + indexer (one lookup vs two).
  • Large LINQ chains on hot paths — profile before optimizing.