C# Aggregate Accumulator

C# Aggregate Accumulator

What is an accumulator? How to use an accumulator? Don't worry, a new technology is basically born to meet a certain need. Starting from the need, it is easier to understand the characteristics of this function.

Last updated 4/20/2022 7:11 AM
遇水寒
6 min read
Category
.NET
Tags
.NET C# Aggregate

1. Requirements

What is an accumulator? How to use an accumulator? Don't worry, the birth of a new technology is basically to meet a certain need. Starting from the requirement makes it easier to understand the characteristics of this function.

To make it easier to understand, suppose there is an int one-dimensional array storing 5 numbers. Calculate the sum of the first value (-1) and the second value (0), getting (-1); then add that result (-1) to the third number (3), getting 2; again add that result (2) to the fourth number (5)… And so on. In essence, it is: int result = -1 + 0 + 3 + 5 + 8;

int[] numbers={-1, 0, 3, 5,8};

1.1 Basic Requirement

// V1.0 version
static void Main(string[] args)
{
    int[] numbers = { -1, 0, 3, 5, 8 };
    int result = numbers[0];
    for (int i = 1; i < numbers.Length; i++)
    {
        result = result + numbers[i];
    }
    Console.WriteLine(result); // Output 15
    Console.ReadKey();
}

1.2 Encapsulate the Algorithm

Extract the core algorithm so that it can work with other int arrays of varying lengths:

// V1.1 version
static void Main(string[] args)
{
    int[] numbers = { -1, 0, 3, 5, 8 };
    var result = Aggregate(numbers);
    Console.WriteLine(result);
    Console.ReadKey();
}

static int Aggregate(int[] array)
{
    int result = array[0];
    for (int i = 1; i < array.Length; i++)
    {
        result = result + array[i];
    }
    return result;
}

1.3 Not Just Addition – Algorithm Substitution

The accumulator should support operations beyond addition, for example:

int result = -1 * 0 * 3 * 5 * 8;

int result = -1 - 0 - 3 - 5 - 8;
// V1.2 version, implements algorithm substitution
// Requires knowledge of delegates and Lambda
static void Main(string[] args)
{
    int[] numbers = { -1, 0, 3, 5, 8 };
    var result = Aggregate(numbers, (result, next) => result * next); // Multiplication
    //var result = Aggregate(numbers, (result, next) => result - next); // Subtraction
    Console.WriteLine(result);
    Console.ReadKey();
}

static int Aggregate(int[] array, Func<int, int, int> func)
{
    int result = array[0];
    for (int i = 1; i < array.Length; i++)
    {
        result = func(result, array[i]);
    }
    return result;
}

1.4 Not Just int Type – Generics

Currently, the algorithm int Aggregate(int[] array, Func<int, int, int> func) only supports the int type. It needs to be extended to any type – generics.

// V1.3 version, implements generics
// Requires knowledge of generics and IEnumerator interface
static void Main(string[] args)
{
    int[] numbers = { -1, 0, 3, 5, 8 };
    var result = Aggregate(numbers, (result, next) => result + next);
    Console.WriteLine(result);
    Console.ReadKey();
}

static TSource Aggregate<TSource>(IEnumerable<TSource> source, Func<TSource, TSource, TSource> func)
{
    using (IEnumerator<TSource> e = source.GetEnumerator())
    {
        if (!e.MoveNext())
        {
            throw new ArgumentException();
        }

        TSource result = e.Current;
        while (e.MoveNext())
        {
            result = func(result, e.Current);
        }

        return result;
    }
}

1.5 Turn into an Extension Method

Directly add an extension method for classes that implement IEnumerator<T>. At this point, the functionality of this Aggregate is similar to the accumulator provided by Microsoft.

// V1.4 version, extension method
class Program
{
    static void Main(string[] args)
    {
        int[] numbers = { -1, 0, 3, 5, 8 };
        var result = numbers.Aggregate((result, next) => result + next);
        Console.WriteLine(result);
        Console.ReadKey();
    }
}

public static class Helper
{
    public static TSource Aggregate<TSource>(this IEnumerable<TSource> source, Func<TSource, TSource, TSource> func)
    {
        using (IEnumerator<TSource> e = source.GetEnumerator())
        {
            if (!e.MoveNext())
            {
                throw new ArgumentException("At least two elements are required.");
            }

            TSource result = e.Current;
            while (e.MoveNext())
            {
                result = func(result, e.Current);
            }

            return result;
        }
    }
}

2. Microsoft’s Provided API

In the System.Linq namespace, the following overloads are available:

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 first interface is identical to the functionality illustrated in my examples above. The other two will be explained later (time permitting).

3. From Simple to Deep

If you are a beginner, your first reaction might be that Aggregate only does addition, subtraction, multiplication, or division. If you think that way, it means you still haven’t grasped it deeply enough. Let’s now analyze the method’s parameter: func.

As shown in the figure below, the accumulator iterates over every element. Except for the first pair (it directly applies func to the first and second elements), starting from the third element, it takes the previous result result as the first input parameter of func, and the next element of the array as the second input parameter. This continues until the end, returning the final result.

Practical use case: When a database table references foreign keys from multiple tables, and you need to query those foreign keys, you can use the accumulator to accumulate the conditions that need to be queried and then query the database.

Keep Exploring

Related Reading

More Articles