Collections & LINQ · Lesson 30

Aggregate with an explicit seed

Describe a fold whose initial state also defines the empty-input result.

How it works

Aggregate repeatedly combines an accumulated state with the next sequence element. The overload with a seed supplies the starting state explicitly. This makes the empty-input behavior clear: if no elements are processed, the seed itself is returned. A fold can calculate more than one property when the accumulator is a tuple or another summary value.

Choose an operation whose state transitions are easy to explain. A simple Sum or Count is usually clearer than an elaborate Aggregate call that only recreates those operations. Aggregate becomes useful when one pass deliberately computes a related set of results, or when the domain has a specific combination rule that is clearer as an accumulator update.

Walk through the example. The accumulator begins with a count of zero and total of zero. Each integer increments the count and adds to the total, producing three values and a total of twelve. Running the same fold on an empty array returns the unchanged seed. The example prints both fields so the empty-input contract can be compared directly with the nonempty case.

Watch the boundary. The seedless overload has a different empty-sequence contract and cannot return a normal result when no initial element exists. Do not switch overloads casually while refactoring. Also avoid mutating shared objects inside an accumulator unless that ownership is explicit. A fresh immutable value on each step is often easier to reason about in a teaching example and in small report calculations.

Practice independently. Fold a sequence of signed adjustments into a tuple containing positive count, negative count, and net total. Define how zero affects the counts. Test an empty batch, all zeros, and a mixture of signs. Compare the result with three separate straightforward calculations, then decide whether one fold is clearer for the actual workflow rather than assuming fewer passes always means a better design.

A working example

using System;
using System.Collections.Generic;
using System.Linq;
using System.Globalization;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;

(int Count, int Total) Summarize(IEnumerable<int> values) =>
    values.Aggregate((Count: 0, Total: 0), (state, value) => (state.Count + 1, state.Total + value));
var full = Summarize(new[] { 3, 4, 5 });
var empty = Summarize(Array.Empty<int>());
Console.WriteLine($"{full.Count}:{full.Total}");
Console.WriteLine($"{empty.Count}:{empty.Total}");

Expected output

3:12
0:0
Try this
The seed is both the starting state and the result for an empty input.