Aggregate Functions
Vaibhav • September 11, 2025
Once you've filtered, projected, sorted, and grouped your data using LINQ, the next natural step is often to summarize it. That’s where aggregate functions come in. These functions allow you to compute totals, averages, minimums, maximums, and other summaries directly from your collections. Whether you're calculating the total sales for a month, the average score of students, or the highest temperature recorded, LINQ’s aggregate functions make it easy to extract meaningful insights from your data.
What Are Aggregate Functions?
Aggregate functions operate on a sequence of values and return a single result. In LINQ, these include methods
like Count
, Sum
, Average
, Min
, Max
, and the more general Aggregate
. These
methods are available in method syntax and can be applied to any collection that implements IEnumerable<T>
.
Aggregate functions are terminal operations - they trigger execution of the LINQ query and return a concrete value, not a deferred sequence.
Counting Elements
The simplest aggregate function is Count
. It returns the number of elements in
a collection. You can use it with or without a predicate.
List fruits = new List { "apple", "banana", "cherry", "apricot" };
int total = fruits.Count();
int startsWithA = fruits.Count(f => f.StartsWith("a"));
The first line counts all fruits. The second line counts only those that start with “a”. The predicate f => f.StartsWith("a")
filters the elements before counting.
Summing Values
Sum
adds up numeric values in a collection. You can sum integers, decimals,
doubles, and even project values before summing.
List scores = new List { 85, 92, 78 };
int totalScore = scores.Sum();
This returns the total score: 255
. If you’re working with objects, you can use
a selector:
class Product
{
public string Name { get; set; }
public decimal Price { get; set; }
}
List products = new List
{
new Product { Name = "Laptop", Price = 999.99m },
new Product { Name = "Tablet", Price = 499.50m },
new Product { Name = "Phone", Price = 799.00m }
};
decimal totalRevenue = products.Sum(p => p.Price);
This computes the total revenue from all products. The lambda p => p.Price
extracts the price from each product.
Calculating Averages
Average
computes the mean of numeric values. It works similarly to Sum
, but returns a floating-point result.
double averageScore = scores.Average();
This returns the average score: 85.0
. You can also use a selector with objects:
double avgPrice = products.Average(p => (double)p.Price);
This casts the decimal price to double before averaging. LINQ requires consistent numeric types for aggregation.
Finding Minimum and Maximum
Min
and Max
return the smallest and largest
values in a collection. These are useful for identifying extremes.
int minScore = scores.Min();
int maxScore = scores.Max();
These return 78
and 92
respectively. With
objects:
decimal cheapest = products.Min(p => p.Price);
decimal mostExpensive = products.Max(p => p.Price);
This finds the lowest and highest product prices. You can use these values to highlight deals or flag outliers.
Using Aggregate for Custom Computations
The Aggregate
method is the most flexible. It lets you define a custom
accumulation logic. For example, concatenating strings:
string sentence = fruits.Aggregate((acc, next) => acc + ", " + next);
This produces: "apple, banana, cherry, apricot"
. The lambda takes the
accumulated value and the next element, and returns the new accumulated value.
Aggregate with Seed Value
You can provide a seed value to start the accumulation. This is useful when the result type differs from the element type.
int totalLength = fruits.Aggregate(0, (acc, fruit) => acc + fruit.Length);
This computes the total number of characters across all fruit names. The seed 0
initializes the accumulator.
Combining Aggregate with Other LINQ Methods
Aggregate functions are often used after filtering, projecting, or grouping. For example, computing the average price of electronics:
decimal avgElectronics = products
.Where(p => p.Name != "Apple" && p.Name != "Banana")
.Average(p => p.Price);
This filters out fruits and averages the price of remaining products. The chaining makes the query expressive and readable.
Handling Empty Sequences
Some aggregate functions throw exceptions on empty sequences. For example, Average
, Min
, and Max
require at least one element. You should check for emptiness before applying
them.
if (scores.Any())
{
double avg = scores.Average();
}
This avoids runtime errors. Alternatively, use DefaultIfEmpty
to provide
fallback values.
double avgSafe = scores.DefaultIfEmpty(0).Average();
This returns 0
if the sequence is empty. It’s a safe way to handle optional
data.
Aggregate Functions and Deferred Execution
Unlike most LINQ methods, aggregate functions trigger immediate execution. They return a concrete value, not a deferred query. This means the underlying collection is enumerated right away.
Note: If your collection is expensive to compute or changes over time, consider caching it
with ToList()
before applying aggregate functions.
Performance Considerations
Aggregate functions are efficient for in-memory collections. They iterate once and compute the result. However, avoid chaining multiple aggregates on the same sequence - it causes repeated enumeration.
var list = scores.ToList();
int min = list.Min();
int max = list.Max();
double avg = list.Average();
This caches the sequence and avoids recomputation. It’s especially important for queries that involve database or network access.
Using Aggregate in Grouped Queries
You can apply aggregate functions to each group in a grouped query. For example, counting employees per department:
var counts = from emp in employees
group emp by emp.DepartmentId into deptGroup
select new { DepartmentId = deptGroup.Key, Count = deptGroup.Count() };
This returns a sequence of anonymous objects with department ID and employee count. You can also compute sums, averages, or other metrics per group.
Common Mistakes to Avoid
A frequent mistake is assuming that Aggregate
is the same as Sum
or Count
. While it can replicate those
behaviors, it’s more general and requires explicit logic. Also, be careful with empty sequences - not all
aggregate functions handle them gracefully.
Use Aggregate
when you need custom
accumulation logic. For standard summaries, prefer Sum
, Average
, Min
, and Max
- they’re optimized and easier to read.
Summary
Aggregate functions in LINQ provide a powerful way to summarize data. Whether you’re counting elements, computing totals, finding extremes, or building custom accumulations, these functions help you extract insights with minimal code. They integrate seamlessly with filtering, projection, and grouping, and support both simple and complex scenarios. By understanding how each function works - and when to use it - you’ll write more expressive, efficient, and insightful LINQ queries.
In the next article, we’ll explore Quantifier Methods - how to check for existence, universality, and emptiness in LINQ collections.