Reputation: 1028
I have a list of values, could be doubles or DateTimes.
15, 36, -7, 12, 8
This data is a TimeSeries, so order matters. Also there are only 3 to 6 values in the list, so we are not talking about a large data set.
Say I want to produce statistics on these, such as ratios.
15/36, 36/-7, -7/12, 12/8 == .417, -5.14, -.583, 1.5
and then ratios of the ratios
.417/-5.14, -5.14/-.583, -.583/1.5
.. and so on.
I also need to generate stats for each value against each value in the past.
12/8, -7/8, 36/8, 15/8
12/-7, 12/36, 12/15
...
Also need ratios of each values to average of previous values.
avg(12,-7) / 8 , avg(12,-7,36) / 8
When data is DateTime will be using TimeSpan. Also need slope, average slope, trend of ratios, trend of slope.. etc..
Basically trying to get as much relevant data as possible. Since its a timeseries, relevant data is restricted to statistics on values to the left of each, as well as the first and last value.
not sure if im looking for a design pattern, a math formula or TimeSeries analysis concepts.
My current design is to do it in steps. A class for ratios of each pair, then a class for ratios of ratios.. etc. Looking for something more abstract.
Is there a design pattern, math formula or TimeSeries concept that would enable me to write a more abstract solution to my problem?
Thanks Stack Overflow!
Upvotes: 0
Views: 410
Reputation: 6026
I think you need to start with abstracting your time series list of numbers. It seems that each set of calculations has to traverse the list differently.
interface IMyList<T>
{
void SetList(IList<T> series);
bool IsDone();
T GetOperand1();
T GetOperand2();
T Calculate(T op1, T op2);
void SetResult(T result);
void Next();
Dictionary<int, IList<T>> GetResults();
}
When you implement each IMyList in each of you classes, you will build into the class exactly how the list should be traversed. I've implemented the your first example. Also notice I did not use recursion. For each type of traversal and calculation you could create a class like this:
public class Ratio : IMyList<double>
{
private Dictionary<int, IList<double>> _results;
private int _currentSeries;
private int _seriesResults;
private int _op1Index;
private int _op2Index;
private bool _bDone;
public Ratio()
{
_op1Index = 0;
_op2Index = 1;
_currentSeries = 0;
_seriesResults = 1;
}
public void SetList(IList<double> series)
{
// the zero entry is the first result set
_results = new Dictionary<int, IList<double>>();
_results.Add(_currentSeries, series);
_results.Add(_seriesResults, new List<double>());
}
public bool IsDone()
{
return _bDone;
}
public double GetOperand1()
{
return _results[_currentSeries][_op1Index];
}
public double GetOperand2()
{
return _results[_currentSeries][_op2Index];
}
public double Calculate(double op1, double op2)
{
return op1 / op2;
}
public void SetResult(double result)
{
_results[_seriesResults].Add(result);
}
public void Next()
{
_op1Index++;
_op2Index++;
if (_op2Index >= _results[_currentSeries].Count())
{
if (_results[_seriesResults].Count == 1)
{
_bDone = true;
}
else
{
_currentSeries++;
_seriesResults++;
_results.Add(_seriesResults, new List<double>());
_op1Index = 0;
_op2Index = 1;
}
}
}
public Dictionary<int, IList<double>> GetResults()
{
return _results;
}
}
To put this in action, the code would be:
List<double> firstList = new List<double>() { 15, 36, -7, 12, 8 };
// the following section could be refactored further by putting the classes
// in a list of IMyList and then looping through it
var rat = new Ratio();
rat.SetList(firstList);
while (!rat.IsDone())
{
double op1 = rat.GetOperand1();
double op2 = rat.GetOperand2();
rat.SetResult(rat.Calculate(op1, op2);
rat.Next();
}
var results = rat.GetResults();
Upvotes: 2