Skip to content
Theory · Lambdas and LINQ · lesson 7 of 10

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:

C#
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()); // 26

Count 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:

C#
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");                   // none

First

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:

C#
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)); // True

Any

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:

  • Count with a lambda checks every item to the end, even when a match has already been found;
  • Any stops 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:

C#
List<int> nums = [5, 2, 8];
int big = nums.First(n => n > 10); // ✗
Console.WriteLine(big);
TEXT
Unhandled exception. System.InvalidOperationException: Sequence contains no matching element

The 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, Any and All return one value, not a sequence; on a query, Count() is written with parentheses.
  • First throws an InvalidOperationException when there is no item, while FirstOrDefault returns 0 or null.
  • Any answers whether a matching item exists and stops at the first one; All gives true for an empty sequence.