patterncsharpMinor
Sequence generators not only for potatoes but also for apples and oranges
Viewed 0 times
potatoesbutorangessequencealsoforonlyandnotgenerators
Problem
The last question about sequence generators Growing potatoes in delayed sequences was only about potatoes. I thougt why not make it work with apples and oranges too so I made it generic.
The base class got a new name and a generic argument and now looks like this:
The
The biggest change undergone however the
To simplify the creation process I also added a new
```
public class FibonacciSequenceFactory
{
public static FibonacciSequence Create
The base class got a new name and a generic argument and now looks like this:
public abstract class GeneratedSequence : IEnumerable
{
protected GeneratedSequence(int count) { Count = count; }
public int Count { get; }
public IEnumerator GetEnumerator() => Generate().Take(Count).GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
protected abstract IEnumerable Generate();
}The
RegularSequence has been upgraded and is now generic too:public class RegularSequence : GeneratedSequence
{
private readonly T _value;
public RegularSequence(T value, int count) : base(count) { _value = value; }
protected override IEnumerable Generate()
{
while (true) yield return _value;
}
}The biggest change undergone however the
FibonnaciSequence. Generics don't support arithmetic operations so I needed to add a lambda for the sum. Now it looks like this:public class FibonacciSequence : GeneratedSequence
{
private T _preview;
private T _current;
private readonly Func _sum;
public FibonacciSequence(T firstTwo, T firstStep, int count, Func sum) : base(count)
{
_sum = sum;
_preview = firstTwo;
_current = _sum(_preview, firstStep);
}
protected override IEnumerable Generate()
{
yield return _preview;
yield return _preview;
yield return _current;
while (true)
{
var newCurrent = _sum(_preview, _current);
yield return newCurrent;
_preview = _current;
_current = newCurrent;
}
}
}To simplify the creation process I also added a new
FibonacciSequenceFactory:```
public class FibonacciSequenceFactory
{
public static FibonacciSequence Create
Solution
A slightly different approach is to avoid the sublclassing and instead feed the generic DelaySequence class with a generator function. It makes it more flexible.
That said I tend to think you overdo a rather simple construct:
EDIT:
In case of a reusable library of functions I would do it the static way:
It has a number of predefined functions and a set of generic as well to be use on the fly.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace CR146856
{
public class MyDelaySequence : IEnumerable
{
Func> m_generator;
int m_count = 0;
///
/// A contructor for a plain sequence of regular delays
///
/// Number of retries.
/// The delay after each retry.
public MyDelaySequence(int count, T delay)
{
m_count = count;
m_generator = () =>
{
return Enumerable.Range(1, count).Select(i => delay);
};
}
///
/// Constructor for a custom delay generator.
///
/// Number of retries.
/// A custom generator of delays between retries.
public MyDelaySequence(int count, Func> generator)
{
m_count = count;
m_generator = generator;
}
public IEnumerator GetEnumerator()
{
return m_generator().Take(m_count).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
class Program
{
static IEnumerable GeometricDelayGenerator()
{
int delay = 1000;
while (true)
{
yield return delay;
delay += delay;
}
}
static IEnumerable FibonacciIntDelayGenerator()
{
int first = 1000;
yield return first;
yield return first;
int second = first + 3000;
yield return second;
while (true)
{
yield return first + second;
int tmp = first;
first = second;
second = first + tmp;
}
}
static IEnumerable FibonacciTimeSpanDelayGenerator()
{
TimeSpan first = TimeSpan.FromSeconds(1);
yield return first;
yield return first;
TimeSpan second = first + TimeSpan.FromSeconds(3);
yield return second;
while (true)
{
yield return first + second;
TimeSpan tmp = first;
first = second;
second = first + tmp;
}
}
static void Main(string[] args)
{
try
{
TimeSpan seqDelay = TimeSpan.FromSeconds(1);
int count = 7;
foreach (var ts in new MyDelaySequence(count, FibonacciTimeSpanDelayGenerator))
{
Console.WriteLine(ts);
}
}
catch (Exception ex)
{
Console.WriteLine($"ERROR: {ex.Message}");
}
Console.WriteLine("END");
Console.ReadLine();
}
}
}That said I tend to think you overdo a rather simple construct:
foreach (var delay in FibonacciIntDelayGenerator().Take(count))
{
Console.WriteLine($"If service not responding wait in {delay} ms and retry.");
}EDIT:
In case of a reusable library of functions I would do it the static way:
public static class MyDelayGenerators
{
public static IEnumerable DelayGenerator(int retries, T initialDelay, Func offsetFunc)
{
T delay = initialDelay;
for (int i = 0; i GeometricDelayGenerator(int retries, T initialDelay, Func sum)
{
return DelayGenerator(retries, initialDelay, sum);
}
public static IEnumerable GeometricDelayGenerator(int retries, int initialDelay)
{
return DelayGenerator(retries, initialDelay, (d) => d + d);
}
public static IEnumerable GeometricDelayGenerator(int retries, TimeSpan initialDelay)
{
return DelayGenerator(retries, initialDelay, (d) => d + d);
}
public static IEnumerable RegularDelayGenerator(int retries, int delay)
{
for (int i = 0; i RegularDelayGenerator(int retries, TimeSpan delay)
{
for (int i = 0; i FibonacciDelayGenerator(int retries, T first, T firstOffset, Func sum)
{
yield return first;
yield return first;
T second = sum(first, firstOffset);
yield return second;
retries -= 3;
for (int i = 0; i FibonacciDelayGenerator(int retries, int first = 1000, int firstOffset = 1000)
{
return FibonacciDelayGenerator(retries, first, firstOffset, (f, s) =>
{
int tmp = f;
f = s;
s = f + tmp;
return s;
});
}
public static IEnumerable FibonacciDelayGenerator(int retries, TimeSpan first, TimeSpan firstOffset)
{
return FibonacciDelayGenerator(retries, first, firstOffset, (f, s) =>
{
TimeSpan tmp = f;
f = s;
s = f + tmp;
return s;
});
}
}It has a number of predefined functions and a set of generic as well to be use on the fly.
Code Snippets
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace CR146856
{
public class MyDelaySequence<T> : IEnumerable<T>
{
Func<IEnumerable<T>> m_generator;
int m_count = 0;
/// <summary>
/// A contructor for a plain sequence of regular delays
/// </summary>
/// <param name="count">Number of retries.</param>
/// <param name="delay">The delay after each retry.</param>
public MyDelaySequence(int count, T delay)
{
m_count = count;
m_generator = () =>
{
return Enumerable.Range(1, count).Select(i => delay);
};
}
/// <summary>
/// Constructor for a custom delay generator.
/// </summary>
/// <param name="count">Number of retries.</param>
/// <param name="generator">A custom generator of delays between retries.</param>
public MyDelaySequence(int count, Func<IEnumerable<T>> generator)
{
m_count = count;
m_generator = generator;
}
public IEnumerator<T> GetEnumerator()
{
return m_generator().Take(m_count).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
class Program
{
static IEnumerable<int> GeometricDelayGenerator()
{
int delay = 1000;
while (true)
{
yield return delay;
delay += delay;
}
}
static IEnumerable<int> FibonacciIntDelayGenerator()
{
int first = 1000;
yield return first;
yield return first;
int second = first + 3000;
yield return second;
while (true)
{
yield return first + second;
int tmp = first;
first = second;
second = first + tmp;
}
}
static IEnumerable<TimeSpan> FibonacciTimeSpanDelayGenerator()
{
TimeSpan first = TimeSpan.FromSeconds(1);
yield return first;
yield return first;
TimeSpan second = first + TimeSpan.FromSeconds(3);
yield return second;
while (true)
{
yield return first + second;
TimeSpan tmp = first;
first = second;
second = first + tmp;
}
}
static void Main(string[] args)
{
try
{
TimeSpan seqDelay = TimeSpan.FromSeconds(1);
int count = 7;
foreach (var ts in new MyDelaySequence<TimeSpan>(count, FibonacciTimeSpanDelayGenerator))
{
Console.WriteLine(ts);
}
}
catch (Exception ex)
{
Console.WriteLine($"ERROR: {ex.Message}");
}
Console.WriteLine("END");
Console.ReadLine();
}
}
}foreach (var delay in FibonacciIntDelayGenerator().Take(count))
{
Console.WriteLine($"If service not responding wait in {delay} ms and retry.");
}public static class MyDelayGenerators
{
public static IEnumerable<T> DelayGenerator<T>(int retries, T initialDelay, Func<T, T> offsetFunc)
{
T delay = initialDelay;
for (int i = 0; i < retries; i++)
{
yield return delay;
delay = offsetFunc(delay);
}
}
public static IEnumerable<T> GeometricDelayGenerator<T>(int retries, T initialDelay, Func<T, T> sum)
{
return DelayGenerator(retries, initialDelay, sum);
}
public static IEnumerable<int> GeometricDelayGenerator(int retries, int initialDelay)
{
return DelayGenerator(retries, initialDelay, (d) => d + d);
}
public static IEnumerable<TimeSpan> GeometricDelayGenerator(int retries, TimeSpan initialDelay)
{
return DelayGenerator(retries, initialDelay, (d) => d + d);
}
public static IEnumerable<int> RegularDelayGenerator(int retries, int delay)
{
for (int i = 0; i < retries; i++)
{
yield return delay;
}
}
public static IEnumerable<TimeSpan> RegularDelayGenerator(int retries, TimeSpan delay)
{
for (int i = 0; i < retries; i++)
{
yield return delay;
}
}
public static IEnumerable<T> FibonacciDelayGenerator<T>(int retries, T first, T firstOffset, Func<T, T, T> sum)
{
yield return first;
yield return first;
T second = sum(first, firstOffset);
yield return second;
retries -= 3;
for (int i = 0; i < retries; i++)
{
T tmp = sum(first, second);
yield return tmp;
first = second;
second = tmp;
}
}
public static IEnumerable<int> FibonacciDelayGenerator(int retries, int first = 1000, int firstOffset = 1000)
{
return FibonacciDelayGenerator(retries, first, firstOffset, (f, s) =>
{
int tmp = f;
f = s;
s = f + tmp;
return s;
});
}
public static IEnumerable<TimeSpan> FibonacciDelayGenerator(int retries, TimeSpan first, TimeSpan firstOffset)
{
return FibonacciDelayGenerator(retries, first, firstOffset, (f, s) =>
{
TimeSpan tmp = f;
f = s;
s = f + tmp;
return s;
});
}
}Context
StackExchange Code Review Q#146856, answer score: 3
Revisions (0)
No revisions yet.