Accumulating sum in one line in C
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
In C#, an accumulating (running) sum transforms a sequence like [1, 2, 3, 4] into [1, 3, 6, 10], where each element is the sum of all preceding elements including itself. You can compute this in one line using LINQ's Aggregate() method, the Scan pattern, or — starting with .NET 6 — a simple foreach with Sum(). For a true running sum that produces a new sequence (not just a final total), combine Select with a captured variable or use Aggregate with a list accumulator.
Running Sum with Select and Closure
The lambda captures sum by reference and mutates it on each iteration. Each call to the lambda adds the current element to sum and returns the new total. This is concise but relies on side effects.
Using Aggregate for a Running Sum
Aggregate applies a function to each element, passing the accumulated result forward. Here the accumulator is a List<int> where each new element is the previous sum plus the current value.
Simple Total Sum (One-Liner)
Running Sum with Zip (No Side Effects)
This approach is pure (no side effects) but has O(n^2) complexity since Take(i+1).Sum() re-sums from the start for each element. It is suitable for small collections but inefficient for large ones.
Scan Extension Method
A Scan extension method is the cleanest solution for running accumulations. It is O(n), lazy (uses yield return), and reusable for any accumulation operation.
Running Sum of Object Properties
Common Pitfalls
- Confusing
Sum()with running sum:numbers.Sum()returns a single total value. For a running sum (cumulative sequence), you needSelectwith a closure,Aggregatewith a list, or a customScanmethod. - Side effects in LINQ queries: Using
Select(x => sum += x)mutates a captured variable, which breaks if the query is enumerated more than once. Each enumeration produces different results. Always call.ToArray()or.ToList()immediately to materialize the result. - O(n^2) running sum with
Take(i+1).Sum(): The pure functional approach re-sums the entire prefix for each element, making it quadratic. For collections larger than a few hundred elements, use the closure orScanapproach instead. - Parallel LINQ (PLINQ) with side effects: Using
.AsParallel().Select(x => sum += x)produces race conditions because multiple threads mutatesumconcurrently. Never use mutable captured variables with PLINQ. - Forgetting
Aggregateseed value:numbers.Aggregate((a, b) => a + b)throwsInvalidOperationExceptionon an empty sequence. Always provide a seed value:numbers.Aggregate(0, (a, b) => a + b).
Summary
numbers.Sum()returns the total — for a running sum, useSelectwith a captured variable orAggregatewith a list accumulator- The closure approach (
sum += xinsideSelect) is the most concise one-liner but relies on side effects - A custom
Scanextension method is the cleanest, most reusable solution for running accumulations - The pure
Take(i+1).Sum()approach is O(n^2) — avoid it for large collections - Always materialize side-effect queries with
.ToArray()to prevent multiple enumeration issues - Never use mutable captured variables with PLINQ — it causes race conditions

