Click here to Skip to main content
Click here to Skip to main content

Cumulating Values with LINQ

By , 27 Jul 2012
 

Introduction

This is a fully generic implementation of the tip described by Mika Wendelius.

Using the Code

The simple extension method which handles a simple accumulation (like the CumulativeSum of the original tip) is this:

/// <summary>
/// Transforms a sequence into a new sequence by accumulating the values by a specified method.
/// </summary>
/// <typeparam name="Titems">
/// The type of the items in the initial and result sequences, and the accumulated value.
/// </typeparam>
/// <param name="sequence">The input sequence.
/// </param>
/// <param name="accumulateOperation">The operation which accumulates the values. 
/// The parameters are (previousAccumulatedValue, itemFromSequence).
/// </param>
/// <returns>A new sequence of the accumulated values.
/// </returns>
public static IEnumerable<Titems> CumulativeSequence<Titems>
	(this IEnumerable<Titems> sequence,
    Func<Titems, Titems, Titems> accumulateOperation)
{
  return CumulativeSequence(sequence, default(Titems), accumulateOperation, a => a);
}

This clearly just defers to a fully parameterized implementation (which is necessary to implement the CumulativePath functionality of the original tip):

/// <summary>
/// Transforms a sequence into a new sequence by accumulating the values by a specified method.
/// </summary>
/// <typeparam name="Titems">
/// The type of the items in the initial sequence.
/// </typeparam>
/// <typeparam name="Taccum">
/// The type of the accumulator object.
/// </typeparam>
/// <typeparam name="Tvalues">
/// The type of the values in the result sequence.
/// </typeparam>
/// <param name="sequence">The input sequence.
/// </param>
/// <param name="accumulatorInitializer">
/// The initializer for the accumulator object.
/// </param>
/// <param name="accumulateOperation">The operation which accumulates the values. 
/// The parameters are (accumulatorObject, itemFromSequence).
/// It returns the updated or new accumulatorObject.
/// </param>
/// <param name="valueOperation">
/// The operation which gets the result sequence value from the accumulator object.
/// </param>
/// <returns>A new sequence of the accumulated values.
/// </returns>
public static IEnumerable<Tvalues> CumulativeSequence<Titems, Taccum, 
			Tvalues>(this IEnumerable<Titems> sequence,
			Taccum accumulatorInitializer,
			Func<Taccum, Titems, Taccum> accumulateOperation,
			Func<Taccum, Tvalues> valueOperation)
{
  Taccum accumulator = accumulatorInitializer;
  return sequence.Select(item => {
    accumulator = accumulateOperation(accumulator, item);
    return valueOperation(accumulator);
  });
}

(using statements are omitted, see the attached code file.)

Here is the usage corresponding to the CumulativeSum (these give the same output as the original tip):

private static decimal Sum(decimal a, decimal b) { return a + b; }
static void Main()
{
  decimal[] numbers = new decimal[] { 1, 3, 5, 7, 11 };
  foreach (decimal partialSum in numbers.CumulativeSequence((a, n) => a + n))
  {
    Debug.Print(" - {0}", partialSum);
  }
  // can use a defined method instead of repeating the same lambda
  Debug.Print("The cumulative sum total is {0}", numbers.CumulativeSequence(Sum).Last());
  // ...

The CumulativePath of the original tip used a StringBuilder for the path accumulation, and is implemented like this:

  // Some random path
  var splitPath = @"C:\Some directory\Some subdirectory\Somefile.txt".Split('\\');

  // Split the path and print out each cumulated portion of the path
  Debug.Print("The path contains the following parts");
  var pathSequence = splitPath.CumulativeSequence(new StringBuilder(),
                                                  (a, p) => {
                                                    if (a.Length != 0)
                                                      a.Append('\\');
                                                    a.Append(p);
                                                    return a;
                                                  },
                                                  a => a.ToString());
  foreach (string partialPath in pathSequence)
  {
    Debug.Print("   - '{0}'", partialPath);
  }
}

History

  • July 27, 2012 - Initial alternative

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Matt T Heffron
Software Developer (Senior)
United States United States
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
Hint: For improved responsiveness ensure Javascript is enabled and choose 'Normal' from the Layout dropdown and hit 'Update'.
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionInclude link to referenced Tip pleasemembertonyt30 Jul '12 - 13:31 
AnswerRe: Include link to referenced Tip please [modified]memberMatt T Heffron30 Jul '12 - 14:47 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web02 | 2.6.130523.1 | Last Updated 27 Jul 2012
Article Copyright 2012 by Matt T Heffron
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid