Back to Blog
C#

C# LINQ Count: Syntax, Predicates, and Performance

c# linq count: Learn how to use the LINQ Count method in C#: basic syntax, predicate overloads, LongCount, and performance considerations for large collections.

LINQCountIEnumerablePerformanceC# CollectionsQuery Operators
Illustration of counting elements in a C# collection using LINQ Count method.

The Count() method in LINQ is one of the most frequently used aggregate operators. It returns the number of elements in an IEnumerable<T> sequence. The basic syntax is straightforward, but the method has overloads and performance characteristics that are easy to overlook. This article covers the c# linq count method in detail, including predicate filtering, LongCount, and when to avoid Count() altogether.

The Count Method and Its Overloads

The simplest form of Count() returns an int representing the total number of elements in the sequence. It is an extension method defined in the System.Linq namespace, so you need using System.Linq; in your file.

using System.Linq; var numbers = new List<int> { 1, 2, 3, 4, 5 }; int total = numbers.Count(); Console.WriteLine(total); // 5

Count() has two overloads:

  • Count() – counts all elements.
  • Count(Func<T, bool> predicate) – counts elements that satisfy a condition.

The predicate overload is often more efficient than filtering with Where and then calling Count(), because it avoids creating an intermediate sequence.

var numbers = new[] { 10, 15, 20, 25, 30 }; int evenCount = numbers.Count(n => n % 2 == 0); Console.WriteLine(evenCount); // 3

Using Count(predicate) to Filter While Counting

The predicate overload evaluates the condition for each element and increments a counter when the condition is true. This is equivalent to numbers.Where(predicate).Count() but uses less memory because no new collection is allocated.

var words = new List<string> { "apple", "banana", "cherry", "date" }; int longWords = words.Count(w => w.Length > 5); Console.WriteLine(longWords); // 2 (banana, cherry)

When the predicate is expensive or the sequence is large, the single-pass behavior of Count(predicate) is preferable. It iterates the source exactly once, applying the predicate inline.

LongCount for Collections Beyond int.MaxValue

The standard Count() returns an int, which has a maximum value of 2,147,483,647. For sequences that could contain more elements, LINQ provides LongCount(), which returns a long. Both overloads mirror Count(): LongCount() and LongCount(predicate).

// Hypothetical large sequence IEnumerable<int> hugeSequence = GetHugeSequence(); long total = hugeSequence.LongCount();

In practice, most in-memory collections cannot exceed int.MaxValue because arrays and lists are limited to that size. However, if you are working with a custom IEnumerable<T> that streams data from an external source, LongCount() is the safe choice.

Performance: Count() vs Count Property on ICollection

One of the most important performance details is that Count() on a sequence that implements ICollection<T> (such as List<T>, T[], or HashSet<T>) does not iterate the sequence. Instead, it uses the Count property of the collection. The LINQ implementation checks for the ICollection<T> interface and returns the property directly, giving O(1) behavior.

var list = new List<int> { 1, 2, 3 }; int count = list.Count(); // Uses ICollection<T>.Count, O(1)

For sequences that do not implement ICollection<T> (e.g., a yield-based iterator or a LINQ query result), Count() must iterate the entire sequence to count the elements, which is O(n). This distinction matters when you call Count() repeatedly on the same lazy sequence.

Source TypeImplementationComplexity
ICollection<T>Returns Count propertyO(1)
IEnumerable<T> (non-collection)Iterates all elementsO(n)

If you need the count of a lazy sequence multiple times, consider materializing it into a List<T> or an array first, but only if the sequence is finite and memory allows.

When to Use Any() Instead of Count() > 0

A common pattern is checking whether a sequence contains at least one element. Using Count() > 0 is often inefficient because Count() must enumerate the entire sequence unless the source is an ICollection<T>. The Any() method stops as soon as it finds the first element, providing O(1) behavior for most sequences.

// Inefficient: counts all elements if (items.Count() > 0) { ... } // Efficient: stops after the first element if (items.Any()) { ... }

Similarly, Any(predicate) is better than Count(predicate) > 0 when you only need to know if a matching element exists. This is a common performance trap in code that processes large collections.

Common Mistakes and Edge Cases

Null Source

Calling Count() on a null sequence throws an ArgumentNullException. Always ensure the source is non-null before invoking the method.

IEnumerable<int>? items = null; // int count = items.Count(); // Throws ArgumentNullException

Deferred Execution and Multiple Enumeration

If the sequence is the result of a deferred LINQ query, calling Count() forces execution of the query. If you call Count() and then iterate the same sequence again, the query may execute twice. This can cause inconsistent results if the underlying data changes between enumerations. To avoid this, materialize the result with ToList() or ToArray() if you need to iterate it multiple times.

var query = source.Where(x => x.IsActive); int activeCount = query.Count(); // Executes query foreach (var item in query) { ... } // Executes query again

Count() on Infinite Sequences

If you call Count() on an infinite sequence (e.g., one generated by Enumerable.Range with no upper bound), the method will never return. This is a logical error, not a runtime exception. Always ensure the sequence is finite before using Count().

Using Count() with GroupBy

Count() is often used inside GroupBy to get the size of each group. The result is an IGrouping<TKey, TElement>, which implements IEnumerable<TElement>, so Count() works naturally.

var orders = new[] { new { Customer = "Alice", Amount = 100 }, new { Customer = "Bob", Amount = 200 }, new { Customer = "Alice", Amount = 150 } }; var customerOrderCounts = orders.GroupBy(o => o.Customer) .Select(g => new { Customer = g.Key, Count = g.Count() });

This pattern is efficient because GroupBy builds the groups internally, and Count() on each group is O(1) if the group is backed by a collection.

Choosing the Right Counting Method

The decision between Count(), LongCount(), and Any() depends on the specific requirement:

  • Use Count() when you need the exact number of elements and the count fits in an int.
  • Use LongCount() when the count may exceed int.MaxValue.
  • Use Any() when you only need to know whether the sequence is non-empty.
  • Use Count(predicate) when you need the count of matching elements and want to avoid an extra Where call.

For performance-sensitive code, be aware of whether the source implements ICollection<T>. If it does, Count() is O(1); otherwise it is O(n). In scenarios where you repeatedly need the count of a lazy sequence, materialize it once and reuse the collection.

Understanding these nuances helps you write efficient, correct C# code when working with LINQ counting operations.

c# linq count: Practical Usage and Code Examples | RYUSLOG DEV