Click here to Skip to main content
12,073,837 members (70,633 online)
Click here to Skip to main content
Add your own
alternative version

Tagged as

Stats

7.1K views
27 downloads
2 bookmarked
Posted

Cumulating Values with LINQ

, 27 Jul 2012 CPOL
Rate this:
Please Sign up or sign in to vote.
This is an alternative for "Cumulating values with LINQ"

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)

Share

About the Author

Matt T Heffron
Software Developer (Senior) Sciex
United States United States
I started programming in Basic on a DECSystem-10 as a Freshman at Caltech in 1974. I quickly transitioned to assembly language, Fortran, and Pascal. As a summer job at JPL, I did analysis of fuel consumption for the Viking Mars Orbiter attitude control system. I also spent a summer doing O/S maintenance at Digital Equipment Corporation.
After graduation, I started developing microprocessor development tools (e.g., cross-compiler, debugger) for Beckman Instruments, a scientific instrument company.
I've worked on custom file-systems, a real-time O/S for Z8000, Expert Systems (SpinPro & PepPro), and internal and external networking support (I was their first webmaster).
I've worked on the DNA analysis system.
I was the console/UI software architect for Ultracentrifuges and protein Capillary Electrophoresis systems.
After 35 years, Danaher having acquired Beckman (now Beckman Coulter), transferred the CE group to become part of Sciex (2014).

You may also be interested in...

Comments and Discussions

 
QuestionInclude link to referenced Tip please Pin
tonyt30-Jul-12 14:31
membertonyt30-Jul-12 14:31 
AnswerRe: Include link to referenced Tip please Pin
Matt T Heffron30-Jul-12 15:47
memberMatt T Heffron30-Jul-12 15:47 

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

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

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