Reading — step 1 of 6
Learn
LINQ in Depth
LINQ treats collections as data pipelines: each operator takes a sequence and yields a new one, so a transformation reads as a chain of small named steps instead of nested loops with flag variables.
Method syntax
var result = nums
.Where(n => n > 0) // keep positives
.Select(n => n * n) // square each
.OrderByDescending(n => n) // biggest first
.Take(5) // top five
.ToList(); // materialize
Each step returns IEnumerable<T> — that's why they chain. This is the syntax you'll see in most real codebases.
Query syntax
The same pipeline, SQL-flavored:
var result = (
from n in nums
where n > 0
orderby n descending
select n * n
).Take(5).ToList();
Both compile to identical method calls. Method syntax covers more operators, so most teams standardize on it.
The operator toolbox
list.Aggregate(0, (acc, n) => acc + n) // reduce / fold
list.Distinct() // unique values
list.SelectMany(s => s.ToCharArray()) // map + flatten (flatMap)
list.Any(x => x > 10) // does at least one match?
list.All(x => x > 0) // do all match?
list.Count(x => x > 0) // how many match
list.FirstOrDefault(x => x == 5) // first match, or default(T)
First throws InvalidOperationException on no match; FirstOrDefault returns the default value. Pick by whether "missing" is an error in your domain.
GroupBy — the one your exercise needs
GroupBy buckets elements by a key. The result is a sequence of IGrouping<TKey, TElement> — each group has a .Key and is itself enumerable:
string[] words = { "the", "cat", "the" };
var groups = words.GroupBy(w => w);
foreach (var g in groups)
Console.WriteLine($"{g.Key}: {g.Count()}");
// the: 2
// cat: 1
Look at that output order: groups come out in FIRST-APPEARANCE order ("the" before "cat"), not sorted. If you want alphabetical, you must say so:
var groups = words.GroupBy(w => w).OrderBy(g => g.Key);
Deferred execution — idiom and trap
Operators like Where and Select don't run when you call them. They build a description of work; execution happens when something iterates it — foreach, ToList(), Count().
The idiom: composition is free. Build a query conditionally, pass it around, stack more operators on — nothing executes until it's consumed, and a First(...) can stop after one element even on a million-item source.
The trap: every iteration re-runs the whole pipeline.
var expensive = data.Where(SlowCheck);
if (expensive.Any()) { } // runs SlowCheck
foreach (var x in expensive) { } // runs SlowCheck AGAIN
If you'll enumerate more than once, call .ToList() once and iterate the list.
Your exercise
Read one line, split on spaces, then use GroupBy + OrderBy to print each unique word as <word>: <count>, alphabetically. For input the cat the dog the cat the grader expects exactly:
cat: 2
dog: 1
the: 3
The two grader-caught mistakes:
- Forgetting
.OrderBy(g => g.Key). PlainGroupByemits first-appearance order, so you'd printthe: 3first — wrong on every multi-word test. - Format drift: colon, then ONE space.
Console.WriteLine($"{g.Key}: {g.Count()}")matches;cat:2orcat : 2fails. And a single-word input likehimust still printhi: 1.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…