Count, Sum, First and Any
The methods from the previous lesson return a new sequence. But data often has to give one answer: how many items fit, what their sum is, which one comes first, whether there is any at all.
At the end of the conveyor belt stands an inspector. They do not repack the boxes but look at the stream as a whole. They count the boxes, weigh them together, take the first one or check whether any of them is faulty. Their answer is not a new belt but one value: a number, a box, a "yes" or a "no".
In LINQ such answers come from methods that return one value:
List<int> nums = [5, 2, 8, 1, 9, 4];
Console.WriteLine(nums.Count(n => n > 3)); // 4
Console.WriteLine(nums.Sum()); // 29
Console.WriteLine(nums.Min()); // 1
Console.WriteLine(nums.Max()); // 9
Console.WriteLine(nums.Where(n => n > 3).Sum()); // 26Count and total
Count
Count() without an argument returns the number of items, and with a lambda, the number of matching ones: the list has four numbers greater than three.
A list also has the property Count, without parentheses. A query has no such property, only the method: nums.Where(n => n > 3).Count(). The line int big = nums.Where(n => n > 3).Count;, without the parentheses, fails with error CS0428: a method name without parentheses is a method group, not a number.
Sum, Min and Max
Sum adds up the items, Min and Max find the smallest and the largest. They can go at the end of a chain: nums.Where(n => n > 3).Sum() adds up only the numbers greater than three and gives 26.
For an empty sequence of numbers Sum returns 0. But Min and Max throw an InvalidOperationException: an empty sequence has neither a smallest nor a largest item.
The first item
To take one item, there are two methods:
List<int> nums = [5, 2, 8, 1, 9, 4];
Console.WriteLine(nums.First()); // 5
Console.WriteLine(nums.First(n => n > 5)); // 8
Console.WriteLine(nums.FirstOrDefault(n => n > 100)); // 0
List<string> names = [];
string? first = names.FirstOrDefault();
Console.WriteLine(first ?? "none"); // noneFirst
First() returns the first item, and First with a lambda returns the first matching one: 8 is the first number greater than five. If there is no such item, First throws an InvalidOperationException. When First() without a lambda is called on an empty sequence, the exception's message is Sequence contains no elements.
FirstOrDefault
When no item fits, FirstOrDefault throws nothing and returns the default value instead: 0 for int and null for string. That is why the variable for a string is declared as string?, and ?? puts in a fallback value.
The catch is that 0 may also be a real item. If a list can hold 0, the answer of FirstOrDefault cannot tell "found a zero" from "found nothing".
Is there any
Sometimes the item itself is not needed, and a "yes" or "no" is enough:
List<int> nums = [5, 2, 8, 1, 9, 4];
Console.WriteLine(nums.Any(n => n > 8)); // True
Console.WriteLine(nums.All(n => n > 0)); // True
Console.WriteLine(nums.All(n => n > 1)); // False
List<int> empty = [];
Console.WriteLine(empty.Any()); // False
Console.WriteLine(empty.All(n => n > 100)); // TrueAny
Any with a lambda answers whether at least one item fits. Without a lambda it answers whether the sequence has any items at all: for an empty list, false.
All
All answers whether every item fits: the number 1 is not greater than 1, so All(n => n > 1) gives false. For an empty sequence All returns true: it has no item that would break the condition.
Any or Count
Interviewers ask why Any(n => n > 8) is better than the check Count(n => n > 8) > 0. The answer has two parts:
Countwith a lambda checks every item to the end, even when a match has already been found;Anystops at the first matching item, and in a long list that can save many checks.
Here the inspector picture is not exact. The inspector sees the whole belt at once, but LINQ methods take items one at a time, and Any and First stop as soon as the answer is found.
Common mistake
The first matching item was taken without a thought that there may be none:
List<int> nums = [5, 2, 8];
int big = nums.First(n => n > 10); // ✗
Console.WriteLine(big);Unhandled exception. System.InvalidOperationException: Sequence contains no matching elementThe program compiles, but it stops at the second line: no number is greater than 10, and First throws an exception. The words no matching element in the message mean that no item fits the condition.
If a matching item may be missing, ask nums.Any(n => n > 10) first, or take FirstOrDefault and check the result.
Key points
Count,Sum,Min,Max,First,AnyandAllreturn one value, not a sequence; on a query,Count()is written with parentheses.Firstthrows anInvalidOperationExceptionwhen there is no item, whileFirstOrDefaultreturns0ornull.Anyanswers whether a matching item exists and stops at the first one;Allgivestruefor an empty sequence.