My answer is very similar to what @Julian did. However, I had already written my solution, I think it does a better job of providing the two aspects of the OP's question:
- How to do this for a sequence of data (like what was originally shown)
- How do use the same capability for one-at-a-time data
You can't easily do this with a generic, there is no way to constrain a type to one that includes addition (if you know of one, let me now). So this is what the transformation class looks like:
public class AccumulateTransformer
{
private int currentState = 0;
public void Clear()
{
currentState = default(int);
}
public int NextValue(int input)
{
currentState += input;
return currentState;
}
public int Current => currentState;
public IEnumerable<int> TransformSequence(IEnumerable<int> inputs, bool clearFirst = true)
{
if (clearFirst)
{
Clear();
}
foreach (var value in inputs)
{
yield return NextValue(value);
}
}
}
And here's some code to test it (using your data):
var transformer = new AccumulateTransformer();
var inputs = new[] {1, 2, 1, 0, 3, 2,};
var results = transformer.TransformSequence(inputs);
Debug.WriteLine(string.Join(", ", from result in results select result.ToString() ));
transformer.Clear();
Debug.WriteLine(transformer.NextValue(1));
Debug.WriteLine(transformer.NextValue(2));
Debug.WriteLine(transformer.NextValue(1));
Debug.WriteLine(transformer.NextValue(0));
Debug.WriteLine(transformer.NextValue(3));
Debug.WriteLine(transformer.NextValue(2));
The output of that looks like:
1, 3, 4, 4, 7, 9
1
3
4
4
7
9
To make this generic, you need a way of doing the accumulation operation that isn't dependent on T understanding addition. To do that, change the code to what's show below.
It makes the type generic on T (which would be int
in this case), but includes a constructor that takes a Func<T, T, T>
that will do the accumulation. When you construct your instance, you provide a Func
that just adds two numbers.
The class code:
public class AccumulateTransformer<T>
{
private T _currentState = default(T);
private Func<T, T, T> _accumulator;
public AccumulateTransformer(Func<T, T, T> accumulator)
{
_accumulator = accumulator;
}
public void Clear()
{
_currentState = default(T);
}
public T NextValue(T input)
{
_currentState = _accumulator(_currentState, input);
return _currentState;
}
public T Current => _currentState;
public IEnumerable<T> TransformSequence(IEnumerable<T> inputs, bool clearFirst = true)
{
if (clearFirst)
{
Clear();
}
foreach (var value in inputs)
{
yield return NextValue(value);
}
}
The only difference in using this is that you have to provide that accumulate Func in the constructor:
var transformer = new AccumulateTransformer<int>((a, b) => a + b);
Otherwise, it's used the same way and produces the same output.