TL/DR
- the
Aggregate
method is an extension method of collections that inherit fromIEnumerable
- the method returns only one value of any type
- It is an accumulation function same as sum, count etc.
- it has 3 overloads
Some weeks ago, I had to display the expected total amount of money to be debited from a list of account in a specific year, month and week, starting from the first day the account was added to the system, based on a condition.
This is different from the summation of all the money to be debited from the account, because:
- there is a condition to be followed in each iteration of the list of accounts
- my return value is a tuple i.e. a tuple of three int values representing week, month and year deductions
The preferred method to use in this case is the Aggregate
method. It is present in all C# collections that inherits from IEnumerable
.
The Aggregate
method performs an operation on each element in a list, taking the previous operations into account. For example, it performs an operation on the first two elements of a list and uses the result to operate on the third element and on and on to return a single value.
Consider this:
int[] numbers = { 1, 2, 3, 4, 5};
//we use aggregate to get the summation of the elements of the list
int summation = numbers.Aggregate((a, b) => a + b);
//summation will be 1 + 2 + 3 + 4 + 5 = 15
Accumulation Function
The Aggregate
method is an accumulation function. An accumulation function combines the rows in a collection, performs an operation on each one of them and returns a single value. There are different accumulation functions in LINQ: Sum, Max, Min, Count and Average, but the Aggregate
method can perform all the operations these methods perform and more.
One other advantage of Aggregate
is that it performs operations on a collection of any type, unlike others that only work with numerical data types.
Consider this:
//flatten a list of countries to a string separated by comma
string[] countries = {"Nigeria", "Ghana", "Togo"};
string countriesToString = countries.Aggregate((a, b) => a + ", " +
b);
//countriesToString will be "Nigeria, Ghana, Togo"
Overloads of the Aggregate Method
The Aggregate
method has three overloads, the first one is explained and used above.
However, I will add the signature of the first overload here and explain in C# terms.
The three overloads are:
1. public static TSource Aggregate<TSource>(this IEnumerable<TSource> source,
Func<TSource, TSource, TSource> func);
2. public static TAccumulate Aggregate<TSource, TAccumulate>(this IEnumerable<TSource> source,
TAccumulate seed,
Func<TAccumulate, TSource, TAccumulate> func);
3. public static TResult Aggregate<TSource, TAccumulate, TResult>(this IEnumerable<TSource> source,
TAccumulate seed,
Func<TAccumulate, TSource, TAccumulate> func,
Func<TAccumulate, TResult> resultSelector);
- The aggregate method is generic, meaning it takes and returns any type, hence, the
Aggregate<TSource>
and others. -
TSource
here is the type of the elements of theEnumerable
we are aggregating over. Thethis
keyword here shows that theAggregate
function is an extension method ofIEnumerable
. -
source
is the collection we are aggregating over. -
Func<TSource, TSource, TSource>
is a delegate that returns the lastTSource
.
This is the same for other overloads. It represents the accumulator operation to be invoked on each element of the collection.
- The second and third overloads have a parameter called seed i.e.
TAccumulate seed
.
This represents the initial accumulator value. It could be any type, it is saying, "start with this value".
The value of this seed determines the return value of the Aggregate
Let us use our numbers example from above.
Let's say we want to add 10 to the sum before adding other elements, this is what we do:
int[] numbers = {1, 2, 3, 4, 5};
//we use the seed parameter:
int summation = numbers.Aggregate(10, (a, b) => a + b);
//summation will be 10 + 1 + 2 + 3 + 4 + 5 = 25
The last overload has an extra delegate Func<TAccumulate, TResult> resultSelector
, which is a function to transform the final value into the result value we want.
It means since the Aggregate
value returns only one value, we can decide to perform another operation on the result we got.
Let's practice this with our countries example from above.
//flatten a list of countries to a string separated by comma
//add another west African country to the start of the list
//then convert these countries to upper case
string[] countries = {"Nigeria", "Ghana", "Togo"};
string countriesToUpper = countries.Aggregate("Liberia", (a, b) => a + ", " +
b, countryString => countryString.ToUpper());
//countriesToUpper will be "LIBERIA, NIGERIA, GHANA, TOGO"
NB: There is a better way to write the code above. We can convert the countries to upper case without the use of this overload.
Instead of using a lambda, we can use define a method outside the code block and use it inside the Aggregator
method.
int[] numbers = {1, 2, 3, 4, 5};
//we use the seed parameter:
int result = numbers.Aggregate(0, (a, b) =>
{
return doMathsOnNumbers(a, b);
});
int doMathsOnNumbers(int first, int second)
{
if (first > second)
return first - second;
return first + second;
};
//result will be 7
This method is fun and you should try it out. It sure will come handy one of these days.
You can read more on the Microsoft docs for this method.
Happy coding. ๐
Top comments (0)