Step 1 of 6 · Reading · ~3 min
Learn
Collections and LINQ
LINQ - Querying Collections
By the end of this lesson you can filter, transform, sort, trim and total a collection by chaining LINQ methods, and you know which ones are lazy and which throw on an empty sequence.
You already know the loop way: create an accumulator, iterate, test with if, update. LINQ (Language INtegrated Query) is the declarative alternative: you describe what you want as a pipeline of operations, and the library does the iterating. Add using System.Linq; and every array and List<T> gains a family of chainable methods.
The building blocks
using System.Linq;
int[] prices = { 30, 12, 45, 12, 8, 19 };
prices.Where(p => p < 20) // filter: 12, 12, 8, 19
prices.Select(p => p * 2) // map: 60, 24, 90, 24, 16, 38
prices.OrderBy(p => p) // sort ascending: 8, 12, 12, 19, 30, 45
prices.OrderByDescending(p => p) // sort descending: 45, 30, 19, 12, 12, 8
prices.Distinct() // drop repeats: 30, 12, 45, 8, 19
prices.Take(2) // first two: 30, 12
prices.Skip(4) // all but first 4: 8, 19
The p => p < 20 syntax is a lambda, a tiny inline function: "given p, return whether p is under 20". Where keeps the elements for which the lambda is true; Select replaces each element with the lambda's result.
Some methods end a pipeline by producing a single value:
prices.Sum() // 126
prices.Max() // 45
prices.Count(p => p > 15) // 3
prices.Any(p => p > 40) // True
prices.First() // 30
To get a collection back, finish with .ToList() or .ToArray(). To print a sequence on one line, use string.Join(", ", sequence).
Chaining: the power is in the order
Each method returns a sequence, so they snap together left to right, and each step receives the output of the one before:
// the two cheapest items under 20
var cheap = prices
.Where(p => p < 20) // 12, 12, 8, 19
.OrderBy(p => p) // 8, 12, 12, 19
.Take(2); // 8, 12
Console.WriteLine(string.Join(" ", cheap)); // 8 12
Say the requirement out loud and translate it word by word. The same steps in another order mean something else:
prices.Take(2).OrderBy(p => p) // 12, 30: first two items, THEN sorted
prices.OrderBy(p => p).Take(2) // 8, 12: sorted, THEN the first two
Laziness and empty sequences
- Deferred execution.
Where,Select,OrderByand the rest do not run when you write them. They run when something consumes the sequence (Sum(),ToList(), aforeach). A chain costs nothing until you pull results through it. - Empty sequences.
Sum()andCount()of an empty sequence return 0. ButMax(),Min(),Average()andFirst()throwInvalidOperationException. When "nothing matched" is a legal outcome, guard withAny()or useFirstOrDefault().
Common mistakes
- Steps in the wrong order.
Takebefore the sort picks from the unsorted data. - Forgetting that
Distinct()is a step of its own. Without it, repeated values stay repeated. - Calling
Max()on a filtered sequence that may be empty. It throws; checkAny()first. - Expecting
OrderByto change the original array. LINQ never modifies its source; it returns a new sequence.
Your exercise
The starter parses a line of integers into nums. Use a LINQ pipeline to print the values the exercise asks for. The most likely mistakes are leaving duplicates in the result and taking the first values before sorting.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…